...
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
$(SUBDIR)x86/swscale_mmx.o: CFLAGS += $(NOREDZONE_FLAGS)
|
||||
|
||||
OBJS += x86/rgb2rgb.o \
|
||||
x86/swscale.o \
|
||||
x86/yuv2rgb.o \
|
||||
|
||||
MMX-OBJS += x86/hscale_fast_bilinear_simd.o \
|
||||
|
||||
OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
|
||||
|
||||
X86ASM-OBJS += x86/input.o \
|
||||
x86/output.o \
|
||||
x86/scale.o \
|
||||
x86/scale_avx2.o \
|
||||
x86/range_convert.o \
|
||||
x86/rgb_2_rgb.o \
|
||||
x86/yuv_2_rgb.o \
|
||||
x86/yuv2yuvX.o \
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2003 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 "../swscale_internal.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/x86/asm.h"
|
||||
#include "libavutil/x86/cpu.h"
|
||||
#include "libavutil/mem_internal.h"
|
||||
|
||||
#define RET 0xC3 // near return opcode for x86
|
||||
#define PREFETCH "prefetchnta"
|
||||
|
||||
#if HAVE_INLINE_ASM
|
||||
av_cold int ff_init_hscaler_mmxext(int dstW, int xInc, uint8_t *filterCode,
|
||||
int16_t *filter, int32_t *filterPos,
|
||||
int numSplits)
|
||||
{
|
||||
uint8_t *fragmentA;
|
||||
x86_reg imm8OfPShufW1A;
|
||||
x86_reg imm8OfPShufW2A;
|
||||
x86_reg fragmentLengthA;
|
||||
uint8_t *fragmentB;
|
||||
x86_reg imm8OfPShufW1B;
|
||||
x86_reg imm8OfPShufW2B;
|
||||
x86_reg fragmentLengthB;
|
||||
int fragmentPos;
|
||||
|
||||
int xpos, i;
|
||||
|
||||
// create an optimized horizontal scaling routine
|
||||
/* This scaler is made of runtime-generated MMXEXT code using specially tuned
|
||||
* pshufw instructions. For every four output pixels, if four input pixels
|
||||
* are enough for the fast bilinear scaling, then a chunk of fragmentB is
|
||||
* used. If five input pixels are needed, then a chunk of fragmentA is used.
|
||||
*/
|
||||
|
||||
// code fragment
|
||||
|
||||
__asm__ volatile (
|
||||
"jmp 9f \n\t"
|
||||
// Begin
|
||||
"0: \n\t"
|
||||
"movq (%%"FF_REG_d", %%"FF_REG_a"), %%mm3 \n\t"
|
||||
"movd (%%"FF_REG_c", %%"FF_REG_S"), %%mm0 \n\t"
|
||||
"movd 1(%%"FF_REG_c", %%"FF_REG_S"), %%mm1 \n\t"
|
||||
"punpcklbw %%mm7, %%mm1 \n\t"
|
||||
"punpcklbw %%mm7, %%mm0 \n\t"
|
||||
"pshufw $0xFF, %%mm1, %%mm1 \n\t"
|
||||
"1: \n\t"
|
||||
"pshufw $0xFF, %%mm0, %%mm0 \n\t"
|
||||
"2: \n\t"
|
||||
"psubw %%mm1, %%mm0 \n\t"
|
||||
"movl 8(%%"FF_REG_b", %%"FF_REG_a"), %%esi \n\t"
|
||||
"pmullw %%mm3, %%mm0 \n\t"
|
||||
"psllw $7, %%mm1 \n\t"
|
||||
"paddw %%mm1, %%mm0 \n\t"
|
||||
|
||||
"movq %%mm0, (%%"FF_REG_D", %%"FF_REG_a") \n\t"
|
||||
|
||||
"add $8, %%"FF_REG_a" \n\t"
|
||||
// End
|
||||
"9: \n\t"
|
||||
"lea " LOCAL_MANGLE(0b) ", %0 \n\t"
|
||||
"lea " LOCAL_MANGLE(1b) ", %1 \n\t"
|
||||
"lea " LOCAL_MANGLE(2b) ", %2 \n\t"
|
||||
"dec %1 \n\t"
|
||||
"dec %2 \n\t"
|
||||
"sub %0, %1 \n\t"
|
||||
"sub %0, %2 \n\t"
|
||||
"lea " LOCAL_MANGLE(9b) ", %3 \n\t"
|
||||
"sub %0, %3 \n\t"
|
||||
|
||||
|
||||
: "=r" (fragmentA), "=r" (imm8OfPShufW1A), "=r" (imm8OfPShufW2A),
|
||||
"=r" (fragmentLengthA)
|
||||
);
|
||||
|
||||
__asm__ volatile (
|
||||
"jmp 9f \n\t"
|
||||
// Begin
|
||||
"0: \n\t"
|
||||
"movq (%%"FF_REG_d", %%"FF_REG_a"), %%mm3 \n\t"
|
||||
"movd (%%"FF_REG_c", %%"FF_REG_S"), %%mm0 \n\t"
|
||||
"punpcklbw %%mm7, %%mm0 \n\t"
|
||||
"pshufw $0xFF, %%mm0, %%mm1 \n\t"
|
||||
"1: \n\t"
|
||||
"pshufw $0xFF, %%mm0, %%mm0 \n\t"
|
||||
"2: \n\t"
|
||||
"psubw %%mm1, %%mm0 \n\t"
|
||||
"movl 8(%%"FF_REG_b", %%"FF_REG_a"), %%esi \n\t"
|
||||
"pmullw %%mm3, %%mm0 \n\t"
|
||||
"psllw $7, %%mm1 \n\t"
|
||||
"paddw %%mm1, %%mm0 \n\t"
|
||||
|
||||
"movq %%mm0, (%%"FF_REG_D", %%"FF_REG_a") \n\t"
|
||||
|
||||
"add $8, %%"FF_REG_a" \n\t"
|
||||
// End
|
||||
"9: \n\t"
|
||||
"lea " LOCAL_MANGLE(0b) ", %0 \n\t"
|
||||
"lea " LOCAL_MANGLE(1b) ", %1 \n\t"
|
||||
"lea " LOCAL_MANGLE(2b) ", %2 \n\t"
|
||||
"dec %1 \n\t"
|
||||
"dec %2 \n\t"
|
||||
"sub %0, %1 \n\t"
|
||||
"sub %0, %2 \n\t"
|
||||
"lea " LOCAL_MANGLE(9b) ", %3 \n\t"
|
||||
"sub %0, %3 \n\t"
|
||||
|
||||
|
||||
: "=r" (fragmentB), "=r" (imm8OfPShufW1B), "=r" (imm8OfPShufW2B),
|
||||
"=r" (fragmentLengthB)
|
||||
);
|
||||
|
||||
xpos = 0; // lumXInc/2 - 0x8000; // difference between pixel centers
|
||||
fragmentPos = 0;
|
||||
|
||||
for (i = 0; i < dstW / numSplits; i++) {
|
||||
int xx = xpos >> 16;
|
||||
|
||||
if ((i & 3) == 0) {
|
||||
int a = 0;
|
||||
int b = ((xpos + xInc) >> 16) - xx;
|
||||
int c = ((xpos + xInc * 2) >> 16) - xx;
|
||||
int d = ((xpos + xInc * 3) >> 16) - xx;
|
||||
int inc = (d + 1 < 4);
|
||||
uint8_t *fragment = inc ? fragmentB : fragmentA;
|
||||
x86_reg imm8OfPShufW1 = inc ? imm8OfPShufW1B : imm8OfPShufW1A;
|
||||
x86_reg imm8OfPShufW2 = inc ? imm8OfPShufW2B : imm8OfPShufW2A;
|
||||
x86_reg fragmentLength = inc ? fragmentLengthB : fragmentLengthA;
|
||||
int maxShift = 3 - (d + inc);
|
||||
int shift = 0;
|
||||
|
||||
if (filterCode) {
|
||||
filter[i] = ((xpos & 0xFFFF) ^ 0xFFFF) >> 9;
|
||||
filter[i + 1] = (((xpos + xInc) & 0xFFFF) ^ 0xFFFF) >> 9;
|
||||
filter[i + 2] = (((xpos + xInc * 2) & 0xFFFF) ^ 0xFFFF) >> 9;
|
||||
filter[i + 3] = (((xpos + xInc * 3) & 0xFFFF) ^ 0xFFFF) >> 9;
|
||||
filterPos[i / 2] = xx;
|
||||
|
||||
memcpy(filterCode + fragmentPos, fragment, fragmentLength);
|
||||
|
||||
filterCode[fragmentPos + imm8OfPShufW1] = (a + inc) |
|
||||
((b + inc) << 2) |
|
||||
((c + inc) << 4) |
|
||||
((d + inc) << 6);
|
||||
filterCode[fragmentPos + imm8OfPShufW2] = a | (b << 2) |
|
||||
(c << 4) |
|
||||
(d << 6);
|
||||
|
||||
if (i + 4 - inc >= dstW)
|
||||
shift = maxShift; // avoid overread
|
||||
else if ((filterPos[i / 2] & 3) <= maxShift)
|
||||
shift = filterPos[i / 2] & 3; // align
|
||||
|
||||
if (shift && i >= shift) {
|
||||
filterCode[fragmentPos + imm8OfPShufW1] += 0x55 * shift;
|
||||
filterCode[fragmentPos + imm8OfPShufW2] += 0x55 * shift;
|
||||
filterPos[i / 2] -= shift;
|
||||
}
|
||||
}
|
||||
|
||||
fragmentPos += fragmentLength;
|
||||
|
||||
if (filterCode)
|
||||
filterCode[fragmentPos] = RET;
|
||||
}
|
||||
xpos += xInc;
|
||||
}
|
||||
if (filterCode)
|
||||
filterPos[((i / 2) + 1) & (~1)] = xpos >> 16; // needed to jump to the next part
|
||||
|
||||
return fragmentPos + 1;
|
||||
}
|
||||
|
||||
void ff_hyscale_fast_mmxext(SwsInternal *c, int16_t *dst,
|
||||
int dstWidth, const uint8_t *src,
|
||||
int srcW, int xInc)
|
||||
{
|
||||
int32_t *filterPos = c->hLumFilterPos;
|
||||
int16_t *filter = c->hLumFilter;
|
||||
void *mmxextFilterCode = c->lumMmxextFilterCode;
|
||||
int i;
|
||||
#if ARCH_X86_64
|
||||
uint64_t retsave;
|
||||
#else
|
||||
#if !HAVE_EBX_AVAILABLE
|
||||
uint64_t ebxsave;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__asm__ volatile(
|
||||
#if ARCH_X86_64
|
||||
"mov -8(%%rsp), %%"FF_REG_a" \n\t"
|
||||
"mov %%"FF_REG_a", %5 \n\t" // retsave
|
||||
#else
|
||||
#if !HAVE_EBX_AVAILABLE
|
||||
"mov %%"FF_REG_b", %5 \n\t" // ebxsave
|
||||
#endif
|
||||
#endif
|
||||
"pxor %%mm7, %%mm7 \n\t"
|
||||
"mov %0, %%"FF_REG_c" \n\t"
|
||||
"mov %1, %%"FF_REG_D" \n\t"
|
||||
"mov %2, %%"FF_REG_d" \n\t"
|
||||
"mov %3, %%"FF_REG_b" \n\t"
|
||||
"xor %%"FF_REG_a", %%"FF_REG_a" \n\t" // i
|
||||
PREFETCH" (%%"FF_REG_c") \n\t"
|
||||
PREFETCH" 32(%%"FF_REG_c") \n\t"
|
||||
PREFETCH" 64(%%"FF_REG_c") \n\t"
|
||||
|
||||
#if ARCH_X86_64
|
||||
#define CALL_MMXEXT_FILTER_CODE \
|
||||
"movl (%%"FF_REG_b"), %%esi \n\t"\
|
||||
"call *%4 \n\t"\
|
||||
"movl (%%"FF_REG_b", %%"FF_REG_a"), %%esi \n\t"\
|
||||
"add %%"FF_REG_S", %%"FF_REG_c" \n\t"\
|
||||
"add %%"FF_REG_a", %%"FF_REG_D" \n\t"\
|
||||
"xor %%"FF_REG_a", %%"FF_REG_a" \n\t"\
|
||||
|
||||
#else
|
||||
#define CALL_MMXEXT_FILTER_CODE \
|
||||
"movl (%%"FF_REG_b"), %%esi \n\t"\
|
||||
"call *%4 \n\t"\
|
||||
"addl (%%"FF_REG_b", %%"FF_REG_a"), %%"FF_REG_c" \n\t"\
|
||||
"add %%"FF_REG_a", %%"FF_REG_D" \n\t"\
|
||||
"xor %%"FF_REG_a", %%"FF_REG_a" \n\t"\
|
||||
|
||||
#endif /* ARCH_X86_64 */
|
||||
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
|
||||
#if ARCH_X86_64
|
||||
"mov %5, %%"FF_REG_a" \n\t"
|
||||
"mov %%"FF_REG_a", -8(%%rsp) \n\t"
|
||||
#else
|
||||
#if !HAVE_EBX_AVAILABLE
|
||||
"mov %5, %%"FF_REG_b" \n\t"
|
||||
#endif
|
||||
#endif
|
||||
:: "m" (src), "m" (dst), "m" (filter), "m" (filterPos),
|
||||
"m" (mmxextFilterCode)
|
||||
#if ARCH_X86_64
|
||||
,"m"(retsave)
|
||||
#else
|
||||
#if !HAVE_EBX_AVAILABLE
|
||||
,"m" (ebxsave)
|
||||
#endif
|
||||
#endif
|
||||
: "%"FF_REG_a, "%"FF_REG_c, "%"FF_REG_d, "%"FF_REG_S, "%"FF_REG_D
|
||||
#if ARCH_X86_64 || HAVE_EBX_AVAILABLE
|
||||
,"%"FF_REG_b
|
||||
#endif
|
||||
);
|
||||
|
||||
for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--)
|
||||
dst[i] = src[srcW-1]*128;
|
||||
}
|
||||
|
||||
void ff_hcscale_fast_mmxext(SwsInternal *c, int16_t *dst1, int16_t *dst2,
|
||||
int dstWidth, const uint8_t *src1,
|
||||
const uint8_t *src2, int srcW, int xInc)
|
||||
{
|
||||
int32_t *filterPos = c->hChrFilterPos;
|
||||
int16_t *filter = c->hChrFilter;
|
||||
void *mmxextFilterCode = c->chrMmxextFilterCode;
|
||||
int i;
|
||||
#if ARCH_X86_64
|
||||
DECLARE_ALIGNED(8, uint64_t, retsave);
|
||||
#else
|
||||
#if !HAVE_EBX_AVAILABLE
|
||||
DECLARE_ALIGNED(8, uint64_t, ebxsave);
|
||||
#endif
|
||||
#endif
|
||||
__asm__ volatile(
|
||||
#if ARCH_X86_64
|
||||
"mov -8(%%rsp), %%"FF_REG_a" \n\t"
|
||||
"mov %%"FF_REG_a", %7 \n\t" // retsave
|
||||
#else
|
||||
#if !HAVE_EBX_AVAILABLE
|
||||
"mov %%"FF_REG_b", %7 \n\t" // ebxsave
|
||||
#endif
|
||||
#endif
|
||||
"pxor %%mm7, %%mm7 \n\t"
|
||||
"mov %0, %%"FF_REG_c" \n\t"
|
||||
"mov %1, %%"FF_REG_D" \n\t"
|
||||
"mov %2, %%"FF_REG_d" \n\t"
|
||||
"mov %3, %%"FF_REG_b" \n\t"
|
||||
"xor %%"FF_REG_a", %%"FF_REG_a" \n\t" // i
|
||||
PREFETCH" (%%"FF_REG_c") \n\t"
|
||||
PREFETCH" 32(%%"FF_REG_c") \n\t"
|
||||
PREFETCH" 64(%%"FF_REG_c") \n\t"
|
||||
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
"xor %%"FF_REG_a", %%"FF_REG_a" \n\t" // i
|
||||
"mov %5, %%"FF_REG_c" \n\t" // src2
|
||||
"mov %6, %%"FF_REG_D" \n\t" // dst2
|
||||
PREFETCH" (%%"FF_REG_c") \n\t"
|
||||
PREFETCH" 32(%%"FF_REG_c") \n\t"
|
||||
PREFETCH" 64(%%"FF_REG_c") \n\t"
|
||||
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
CALL_MMXEXT_FILTER_CODE
|
||||
|
||||
#if ARCH_X86_64
|
||||
"mov %7, %%"FF_REG_a" \n\t"
|
||||
"mov %%"FF_REG_a", -8(%%rsp) \n\t"
|
||||
#else
|
||||
#if !HAVE_EBX_AVAILABLE
|
||||
"mov %7, %%"FF_REG_b" \n\t"
|
||||
#endif
|
||||
#endif
|
||||
:: "m" (src1), "m" (dst1), "m" (filter), "m" (filterPos),
|
||||
"m" (mmxextFilterCode), "m" (src2), "m"(dst2)
|
||||
#if ARCH_X86_64
|
||||
,"m"(retsave)
|
||||
#else
|
||||
#if !HAVE_EBX_AVAILABLE
|
||||
,"m" (ebxsave)
|
||||
#endif
|
||||
#endif
|
||||
: "%"FF_REG_a, "%"FF_REG_c, "%"FF_REG_d, "%"FF_REG_S, "%"FF_REG_D
|
||||
#if ARCH_X86_64 || HAVE_EBX_AVAILABLE
|
||||
,"%"FF_REG_b
|
||||
#endif
|
||||
);
|
||||
|
||||
for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--) {
|
||||
dst1[i] = src1[srcW-1]*128;
|
||||
dst2[i] = src2[srcW-1]*128;
|
||||
}
|
||||
}
|
||||
#endif //HAVE_INLINE_ASM
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,973 @@
|
||||
;******************************************************************************
|
||||
;* x86-optimized vertical line scaling functions
|
||||
;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@gmail.com>
|
||||
;* Kieran Kunhya <kieran@kunhya.com>
|
||||
;* (c) 2020 Nelson Gomez <nelson.gomez@microsoft.com>
|
||||
;*
|
||||
;* 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_RODATA 32
|
||||
|
||||
minshort: times 8 dw 0x8000
|
||||
yuv2yuvX_16_start: times 4 dd 0x4000 - 0x40000000
|
||||
yuv2yuvX_10_start: times 4 dd 0x10000
|
||||
yuv2yuvX_9_start: times 4 dd 0x20000
|
||||
yuv2yuvX_10_upper: times 8 dw 0x3ff
|
||||
yuv2yuvX_9_upper: times 8 dw 0x1ff
|
||||
pd_4: times 4 dd 4
|
||||
pd_4min0x40000:times 4 dd 4 - (0x40000)
|
||||
pw_16: times 8 dw 16
|
||||
pw_32: times 8 dw 32
|
||||
pd_255: times 8 dd 255
|
||||
pw_512: times 8 dw 512
|
||||
pw_1024: times 8 dw 1024
|
||||
pd_65535_invf: times 8 dd 0x37800080 ;1.0/65535.0
|
||||
pd_yuv2gbrp16_start: times 8 dd -0x40000000
|
||||
pd_yuv2gbrp_y_start: times 8 dd (1 << 9)
|
||||
pd_yuv2gbrp_uv_start: times 8 dd ((1 << 9) - (128 << 19))
|
||||
pd_yuv2gbrp_a_start: times 8 dd (1 << 18)
|
||||
pd_yuv2gbrp16_offset: times 8 dd 0x10000 ;(1 << 16)
|
||||
pd_yuv2gbrp16_round13: times 8 dd 0xE0002000 ;(1 << 13) - (1 << 29)
|
||||
pd_yuv2gbrp16_a_offset: times 8 dd 0x20002000
|
||||
pd_yuv2gbrp16_upper30: times 8 dd 0x3FFFFFFF ;(1<<30) - 1
|
||||
pd_yuv2gbrp16_upper27: times 8 dd 0x07FFFFFF ;(1<<27) - 1
|
||||
pd_yuv2gbrp16_upper16: times 8 dd 0x0000FFFF ;(1<<16) - 1
|
||||
pd_yuv2gbrp16_upperC: times 8 dd 0xC0000000
|
||||
pd_yuv2gbrp_debias: times 8 dd 0x00008000 ;(1 << 29 - 14)
|
||||
pb_pack_shuffle8: db 0, 4, 8, 12, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
0, 4, 8, 12, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1
|
||||
pb_pack_shuffle16le: db 0, 1, 4, 5, \
|
||||
8, 9, 12, 13, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
0, 1, 4, 5, \
|
||||
8, 9, 12, 13
|
||||
pb_pack_shuffle16be: db 1, 0, 5, 4, \
|
||||
9, 8, 13, 12, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
1, 0, 5, 4, \
|
||||
9, 8, 13, 12
|
||||
pb_shuffle32be: db 3, 2, 1, 0, \
|
||||
7, 6, 5, 4, \
|
||||
11, 10, 9, 8, \
|
||||
15, 14, 13, 12, \
|
||||
3, 2, 1, 0, \
|
||||
7, 6, 5, 4, \
|
||||
11, 10, 9, 8, \
|
||||
15, 14, 13, 12
|
||||
yuv2nv12_shuffle_mask: times 2 db 0, 4, 8, 12, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1
|
||||
yuv2nv21_shuffle_mask: times 2 db 4, 0, 12, 8, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1, \
|
||||
-1, -1, -1, -1
|
||||
yuv2nv12_permute_mask: dd 0, 4, 1, 2, 3, 5, 6, 7
|
||||
|
||||
SECTION .text
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; vertical line scaling
|
||||
;
|
||||
; void yuv2plane1_<output_size>_<opt>(const int16_t *src, uint8_t *dst, int dstW,
|
||||
; const uint8_t *dither, int offset)
|
||||
; and
|
||||
; void yuv2planeX_<output_size>_<opt>(const int16_t *filter, int filterSize,
|
||||
; const int16_t **src, uint8_t *dst, int dstW,
|
||||
; const uint8_t *dither, int offset)
|
||||
;
|
||||
; Scale one or $filterSize lines of source data to generate one line of output
|
||||
; data. The input is 15 bits in int16_t if $output_size is [8,10] and 19 bits in
|
||||
; int32_t if $output_size is 16. $filter is 12 bits. $filterSize is a multiple
|
||||
; of 2. $offset is either 0 or 3. $dither holds 8 values.
|
||||
;-----------------------------------------------------------------------------
|
||||
%macro yuv2planeX_mainloop 2
|
||||
.pixelloop_%2:
|
||||
%assign %%i 0
|
||||
; the rep here is for the 8-bit output MMX case, where dither covers
|
||||
; 8 pixels but we can only handle 2 pixels per register, and thus 4
|
||||
; pixels per iteration. In order to not have to keep track of where
|
||||
; we are w.r.t. dithering, we unroll the MMX/8-bit loop x2.
|
||||
%if %1 == 8
|
||||
%assign %%repcnt 16/mmsize
|
||||
%else
|
||||
%assign %%repcnt 1
|
||||
%endif
|
||||
|
||||
%rep %%repcnt
|
||||
|
||||
%if %1 == 8
|
||||
%if ARCH_X86_32
|
||||
mova m2, [rsp+mmsize*(0+%%i)]
|
||||
mova m1, [rsp+mmsize*(1+%%i)]
|
||||
%else ; x86-64
|
||||
mova m2, m8
|
||||
mova m1, m_dith
|
||||
%endif ; x86-32/64
|
||||
%else ; %1 == 9/10/16
|
||||
mova m1, [yuv2yuvX_%1_start]
|
||||
mova m2, m1
|
||||
%endif ; %1 == 8/9/10/16
|
||||
movsx cntr_reg, fltsizem
|
||||
.filterloop_%2_ %+ %%i:
|
||||
; input pixels
|
||||
mov r6, [srcq+gprsize*cntr_reg-2*gprsize]
|
||||
%if %1 == 16
|
||||
mova m3, [r6+r5*4]
|
||||
mova m5, [r6+r5*4+mmsize]
|
||||
%else ; %1 == 8/9/10
|
||||
mova m3, [r6+r5*2]
|
||||
%endif ; %1 == 8/9/10/16
|
||||
mov r6, [srcq+gprsize*cntr_reg-gprsize]
|
||||
%if %1 == 16
|
||||
mova m4, [r6+r5*4]
|
||||
mova m6, [r6+r5*4+mmsize]
|
||||
%else ; %1 == 8/9/10
|
||||
mova m4, [r6+r5*2]
|
||||
%endif ; %1 == 8/9/10/16
|
||||
|
||||
; coefficients
|
||||
movd m0, [filterq+2*cntr_reg-4] ; coeff[0], coeff[1]
|
||||
%if %1 == 16
|
||||
pshuflw m7, m0, 0 ; coeff[0]
|
||||
pshuflw m0, m0, 0x55 ; coeff[1]
|
||||
pmovsxwd m7, m7 ; word -> dword
|
||||
pmovsxwd m0, m0 ; word -> dword
|
||||
|
||||
pmulld m3, m7
|
||||
pmulld m5, m7
|
||||
pmulld m4, m0
|
||||
pmulld m6, m0
|
||||
|
||||
paddd m2, m3
|
||||
paddd m1, m5
|
||||
paddd m2, m4
|
||||
paddd m1, m6
|
||||
%else ; %1 == 10/9/8
|
||||
punpcklwd m5, m3, m4
|
||||
punpckhwd m3, m4
|
||||
SPLATD m0
|
||||
|
||||
pmaddwd m5, m0
|
||||
pmaddwd m3, m0
|
||||
|
||||
paddd m2, m5
|
||||
paddd m1, m3
|
||||
%endif ; %1 == 8/9/10/16
|
||||
|
||||
sub cntr_reg, 2
|
||||
jg .filterloop_%2_ %+ %%i
|
||||
|
||||
%if %1 == 16
|
||||
psrad m2, 31 - %1
|
||||
psrad m1, 31 - %1
|
||||
%else ; %1 == 10/9/8
|
||||
psrad m2, 27 - %1
|
||||
psrad m1, 27 - %1
|
||||
%endif ; %1 == 8/9/10/16
|
||||
|
||||
%if %1 == 8
|
||||
packssdw m2, m1
|
||||
packuswb m2, m2
|
||||
movh [dstq+r5*1], m2
|
||||
%else ; %1 == 9/10/16
|
||||
%if %1 == 16
|
||||
packssdw m2, m1
|
||||
paddw m2, [minshort]
|
||||
%else ; %1 == 9/10
|
||||
%if cpuflag(sse4)
|
||||
packusdw m2, m1
|
||||
%else ; mmxext/sse2
|
||||
packssdw m2, m1
|
||||
pmaxsw m2, m6
|
||||
%endif ; mmxext/sse2/sse4/avx
|
||||
pminsw m2, [yuv2yuvX_%1_upper]
|
||||
%endif ; %1 == 9/10/16
|
||||
mov%2 [dstq+r5*2], m2
|
||||
%endif ; %1 == 8/9/10/16
|
||||
|
||||
add r5, mmsize/2
|
||||
sub wd, mmsize/2
|
||||
|
||||
%assign %%i %%i+2
|
||||
%endrep
|
||||
jg .pixelloop_%2
|
||||
%endmacro
|
||||
|
||||
%macro yuv2planeX_fn 3
|
||||
|
||||
%if ARCH_X86_32
|
||||
%define cntr_reg fltsizeq
|
||||
%define movsx mov
|
||||
%else
|
||||
%define cntr_reg r7
|
||||
%define movsx movsxd
|
||||
%endif
|
||||
|
||||
cglobal yuv2planeX_%1, %3, 8, %2, filter, fltsize, src, dst, w, dither, offset
|
||||
%if %1 == 8 || %1 == 9 || %1 == 10
|
||||
pxor m6, m6
|
||||
%endif ; %1 == 8/9/10
|
||||
|
||||
%if %1 == 8
|
||||
%if ARCH_X86_32
|
||||
%assign pad 0x2c - (stack_offset & 15)
|
||||
SUB rsp, pad
|
||||
%define m_dith m7
|
||||
%else ; x86-64
|
||||
%define m_dith m9
|
||||
%endif ; x86-32
|
||||
|
||||
; create registers holding dither
|
||||
movq m_dith, [ditherq] ; dither
|
||||
test offsetd, offsetd
|
||||
jz .no_rot
|
||||
%if mmsize == 16
|
||||
punpcklqdq m_dith, m_dith
|
||||
%endif ; mmsize == 16
|
||||
PALIGNR m_dith, m_dith, 3, m0
|
||||
.no_rot:
|
||||
%if mmsize == 16
|
||||
punpcklbw m_dith, m6
|
||||
%if ARCH_X86_64
|
||||
punpcklwd m8, m_dith, m6
|
||||
pslld m8, 12
|
||||
%else ; x86-32
|
||||
punpcklwd m5, m_dith, m6
|
||||
pslld m5, 12
|
||||
%endif ; x86-32/64
|
||||
punpckhwd m_dith, m6
|
||||
pslld m_dith, 12
|
||||
%if ARCH_X86_32
|
||||
mova [rsp+ 0], m5
|
||||
mova [rsp+16], m_dith
|
||||
%endif
|
||||
%else ; mmsize == 8
|
||||
punpcklbw m5, m_dith, m6
|
||||
punpckhbw m_dith, m6
|
||||
punpcklwd m4, m5, m6
|
||||
punpckhwd m5, m6
|
||||
punpcklwd m3, m_dith, m6
|
||||
punpckhwd m_dith, m6
|
||||
pslld m4, 12
|
||||
pslld m5, 12
|
||||
pslld m3, 12
|
||||
pslld m_dith, 12
|
||||
mova [rsp+ 0], m4
|
||||
mova [rsp+ 8], m5
|
||||
mova [rsp+16], m3
|
||||
mova [rsp+24], m_dith
|
||||
%endif ; mmsize == 8/16
|
||||
%endif ; %1 == 8
|
||||
|
||||
xor r5, r5
|
||||
|
||||
%if mmsize == 8 || %1 == 8
|
||||
yuv2planeX_mainloop %1, a
|
||||
%else ; mmsize == 16
|
||||
test dstq, 15
|
||||
jnz .unaligned
|
||||
yuv2planeX_mainloop %1, a
|
||||
RET
|
||||
.unaligned:
|
||||
yuv2planeX_mainloop %1, u
|
||||
%endif ; mmsize == 8/16
|
||||
|
||||
%if %1 == 8
|
||||
%if ARCH_X86_32
|
||||
ADD rsp, pad
|
||||
RET
|
||||
%else ; x86-64
|
||||
RET
|
||||
%endif ; x86-32/64
|
||||
%else ; %1 == 9/10/16
|
||||
RET
|
||||
%endif ; %1 == 8/9/10/16
|
||||
%endmacro
|
||||
|
||||
%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0
|
||||
INIT_MMX mmxext
|
||||
yuv2planeX_fn 8, 0, 7
|
||||
%endif
|
||||
|
||||
INIT_XMM sse2
|
||||
yuv2planeX_fn 8, 10, 7
|
||||
yuv2planeX_fn 9, 7, 5
|
||||
yuv2planeX_fn 10, 7, 5
|
||||
|
||||
INIT_XMM sse4
|
||||
yuv2planeX_fn 8, 10, 7
|
||||
yuv2planeX_fn 9, 7, 5
|
||||
yuv2planeX_fn 10, 7, 5
|
||||
yuv2planeX_fn 16, 8, 5
|
||||
|
||||
%if HAVE_AVX_EXTERNAL
|
||||
INIT_XMM avx
|
||||
yuv2planeX_fn 8, 10, 7
|
||||
yuv2planeX_fn 9, 7, 5
|
||||
yuv2planeX_fn 10, 7, 5
|
||||
%endif
|
||||
|
||||
; %1=outout-bpc, %2=alignment (u/a)
|
||||
%macro yuv2plane1_mainloop 2
|
||||
.loop_%2:
|
||||
%if %1 == 8
|
||||
paddsw m0, m2, [srcq+wq*2+mmsize*0]
|
||||
paddsw m1, m3, [srcq+wq*2+mmsize*1]
|
||||
psraw m0, 7
|
||||
psraw m1, 7
|
||||
packuswb m0, m1
|
||||
mov%2 [dstq+wq], m0
|
||||
%elif %1 == 16
|
||||
paddd m0, m4, [srcq+wq*4+mmsize*0]
|
||||
paddd m1, m4, [srcq+wq*4+mmsize*1]
|
||||
paddd m2, m4, [srcq+wq*4+mmsize*2]
|
||||
paddd m3, m4, [srcq+wq*4+mmsize*3]
|
||||
psrad m0, 3
|
||||
psrad m1, 3
|
||||
psrad m2, 3
|
||||
psrad m3, 3
|
||||
%if cpuflag(sse4) ; avx/sse4
|
||||
packusdw m0, m1
|
||||
packusdw m2, m3
|
||||
%else ; mmx/sse2
|
||||
packssdw m0, m1
|
||||
packssdw m2, m3
|
||||
paddw m0, m5
|
||||
paddw m2, m5
|
||||
%endif ; mmx/sse2/sse4/avx
|
||||
mov%2 [dstq+wq*2+mmsize*0], m0
|
||||
mov%2 [dstq+wq*2+mmsize*1], m2
|
||||
%else ; %1 == 9/10
|
||||
paddsw m0, m2, [srcq+wq*2+mmsize*0]
|
||||
paddsw m1, m2, [srcq+wq*2+mmsize*1]
|
||||
psraw m0, 15 - %1
|
||||
psraw m1, 15 - %1
|
||||
pmaxsw m0, m4
|
||||
pmaxsw m1, m4
|
||||
pminsw m0, m3
|
||||
pminsw m1, m3
|
||||
mov%2 [dstq+wq*2+mmsize*0], m0
|
||||
mov%2 [dstq+wq*2+mmsize*1], m1
|
||||
%endif
|
||||
add wq, mmsize
|
||||
jl .loop_%2
|
||||
%endmacro
|
||||
|
||||
%macro yuv2plane1_fn 3
|
||||
cglobal yuv2plane1_%1, %3, %3, %2, src, dst, w, dither, offset
|
||||
movsxdifnidn wq, wd
|
||||
add wq, mmsize - 1
|
||||
and wq, ~(mmsize - 1)
|
||||
%if %1 == 8
|
||||
add dstq, wq
|
||||
%else ; %1 != 8
|
||||
lea dstq, [dstq+wq*2]
|
||||
%endif ; %1 == 8
|
||||
%if %1 == 16
|
||||
lea srcq, [srcq+wq*4]
|
||||
%else ; %1 != 16
|
||||
lea srcq, [srcq+wq*2]
|
||||
%endif ; %1 == 16
|
||||
neg wq
|
||||
|
||||
%if %1 == 8
|
||||
pxor m4, m4 ; zero
|
||||
|
||||
; create registers holding dither
|
||||
movq m3, [ditherq] ; dither
|
||||
test offsetd, offsetd
|
||||
jz .no_rot
|
||||
punpcklqdq m3, m3
|
||||
PALIGNR m3, m3, 3, m2
|
||||
.no_rot:
|
||||
punpcklbw m3, m4
|
||||
mova m2, m3
|
||||
%elif %1 == 9
|
||||
pxor m4, m4
|
||||
mova m3, [pw_512]
|
||||
mova m2, [pw_32]
|
||||
%elif %1 == 10
|
||||
pxor m4, m4
|
||||
mova m3, [pw_1024]
|
||||
mova m2, [pw_16]
|
||||
%else ; %1 == 16
|
||||
%if cpuflag(sse4) ; sse4/avx
|
||||
mova m4, [pd_4]
|
||||
%else ; sse2
|
||||
mova m4, [pd_4min0x40000]
|
||||
mova m5, [minshort]
|
||||
%endif ; sse2/sse4/avx
|
||||
%endif ; %1 == ..
|
||||
|
||||
; actual pixel scaling
|
||||
test dstq, 15
|
||||
jnz .unaligned
|
||||
yuv2plane1_mainloop %1, a
|
||||
RET
|
||||
.unaligned:
|
||||
yuv2plane1_mainloop %1, u
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
yuv2plane1_fn 8, 5, 5
|
||||
yuv2plane1_fn 9, 5, 3
|
||||
yuv2plane1_fn 10, 5, 3
|
||||
yuv2plane1_fn 16, 6, 3
|
||||
|
||||
INIT_XMM sse4
|
||||
yuv2plane1_fn 16, 5, 3
|
||||
|
||||
%if HAVE_AVX_EXTERNAL
|
||||
INIT_XMM avx
|
||||
yuv2plane1_fn 8, 5, 5
|
||||
yuv2plane1_fn 9, 5, 3
|
||||
yuv2plane1_fn 10, 5, 3
|
||||
yuv2plane1_fn 16, 5, 3
|
||||
%endif
|
||||
|
||||
%undef movsx
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; AVX2 yuv2nv12cX implementation
|
||||
;
|
||||
; void ff_yuv2nv12cX_avx2(enum AVPixelFormat format, const uint8_t *dither,
|
||||
; const int16_t *filter, int filterSize,
|
||||
; const int16_t **u, const int16_t **v,
|
||||
; uint8_t *dst, int dstWidth)
|
||||
;
|
||||
; void ff_yuv2nv21cX_avx2(enum AVPixelFormat format, const uint8_t *dither,
|
||||
; const int16_t *filter, int filterSize,
|
||||
; const int16_t **u, const int16_t **v,
|
||||
; uint8_t *dst, int dstWidth)
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
%if ARCH_X86_64
|
||||
%macro yuv2nv12cX_fn 1
|
||||
cglobal %1cX, 8, 11, 13, tmp1, dither, filter, filterSize, u, v, dst, dstWidth
|
||||
|
||||
mov tmp1q, qword [ditherq]
|
||||
movq xm0, tmp1q
|
||||
ror tmp1q, 24
|
||||
movq xm1, tmp1q
|
||||
|
||||
pmovzxbd m0, xm0
|
||||
pslld m0, m0, 12 ; ditherLo
|
||||
pmovzxbd m1, xm1
|
||||
pslld m1, m1, 12 ; ditherHi
|
||||
|
||||
pxor m9, m9 ; uint8_min dwords
|
||||
mova m10, [pd_255] ; uint8_max dwords
|
||||
mova m11, [%1_shuffle_mask] ; shuffle_mask
|
||||
mova m12, [yuv2nv12_permute_mask] ; permute mask
|
||||
|
||||
DEFINE_ARGS tmp1, tmp2, filter, filterSize, u, v, dst, dstWidth
|
||||
|
||||
xor r8q, r8q
|
||||
|
||||
nv12_outer_%1:
|
||||
mova m2, m0 ; resultLo
|
||||
mova m3, m1 ; resultHi
|
||||
xor r9q, r9q
|
||||
|
||||
nv12_inner_%1:
|
||||
movsx r10d, word [filterq + (2 * r9q)]
|
||||
movd xm4, r10d
|
||||
vpbroadcastd m4, xm4 ; filter
|
||||
|
||||
mov tmp1q, [uq + (gprsize * r9q)]
|
||||
mova xm7, oword [tmp1q + 2 * r8q]
|
||||
|
||||
mov tmp2q, [vq + (gprsize * r9q)]
|
||||
mova xm8, oword [tmp2q + 2 * r8q]
|
||||
|
||||
punpcklwd xm5, xm7, xm8
|
||||
pmovsxwd m5, xm5 ; multiplicandsLo
|
||||
punpckhwd xm6, xm7, xm8
|
||||
pmovsxwd m6, xm6 ; multiplicandsHi
|
||||
|
||||
pmulld m7, m5, m4 ; mulResultLo
|
||||
pmulld m8, m6, m4 ; mulResultHi
|
||||
paddd m2, m2, m7 ; resultLo += mulResultLo
|
||||
paddd m3, m3, m8 ; resultHi += mulResultHi
|
||||
|
||||
inc r9d
|
||||
cmp r9d, filterSized
|
||||
jl nv12_inner_%1
|
||||
; end of inner loop
|
||||
|
||||
psrad m2, m2, 19
|
||||
psrad m3, m3, 19
|
||||
|
||||
; Vectorized av_clip_uint8
|
||||
pmaxsd m2, m2, m9
|
||||
pmaxsd m3, m3, m9
|
||||
pminsd m2, m2, m10
|
||||
pminsd m3, m3, m10
|
||||
|
||||
; At this point we have clamped uint8s arranged in this order:
|
||||
; m2: u1 0 0 0 v1 0 0 0 [...]
|
||||
; m3: u5 0 0 0 v5 0 0 0 [...]
|
||||
;
|
||||
; First, we shuffle the bytes to make the bytes semi-contiguous.
|
||||
; AVX-2 doesn't have cross-lane shuffling, so we'll end up with:
|
||||
; m2: u1 v1 u2 v2 0 0 0 0 0 0 0 0 u3 v3 u4 v4
|
||||
; m3: u5 v5 u6 v6 0 0 0 0 0 0 0 0 u7 v7 u8 v8
|
||||
pshufb m2, m2, m11
|
||||
pshufb m3, m3, m11
|
||||
|
||||
; To fix the cross-lane shuffling issue, we'll then use cross-lane
|
||||
; permutation to combine the two segments
|
||||
vpermd m2, m12, m2
|
||||
vpermd m3, m12, m3
|
||||
|
||||
; Now we have the final results in the lower 8 bytes of each register
|
||||
movq [dstq], xm2
|
||||
movq [dstq + 8], xm3
|
||||
|
||||
add r8d, 8
|
||||
add dstq, 16
|
||||
|
||||
cmp r8d, dstWidthd
|
||||
jl nv12_outer_%1
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
%if HAVE_AVX2_EXTERNAL
|
||||
INIT_YMM avx2
|
||||
yuv2nv12cX_fn yuv2nv12
|
||||
yuv2nv12cX_fn yuv2nv21
|
||||
%endif
|
||||
%endif ; ARCH_X86_64
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; planar grb yuv2anyX functions
|
||||
; void ff_yuv2<gbr_format>_full_X_<opt>(SwsInternal *c, const int16_t *lumFilter,
|
||||
; const int16_t **lumSrcx, int lumFilterSize,
|
||||
; const int16_t *chrFilter, const int16_t **chrUSrcx,
|
||||
; const int16_t **chrVSrcx, int chrFilterSize,
|
||||
; const int16_t **alpSrcx, uint8_t **dest,
|
||||
; int dstW, int y)
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
%if ARCH_X86_64
|
||||
struc SwsInternal
|
||||
.padding: resb 40348 ; offsetof(SwsInternal, yuv2rgb_y_offset)
|
||||
.yuv2rgb_y_offset: resd 1
|
||||
.yuv2rgb_y_coeff: resd 1
|
||||
.yuv2rgb_v2r_coeff: resd 1
|
||||
.yuv2rgb_v2g_coeff: resd 1
|
||||
.yuv2rgb_u2g_coeff: resd 1
|
||||
.yuv2rgb_u2b_coeff: resd 1
|
||||
endstruc
|
||||
|
||||
%define R m0
|
||||
%define G m1
|
||||
%define B m2
|
||||
%define A m3
|
||||
|
||||
%define Y m4
|
||||
%define U m5
|
||||
%define V m6
|
||||
|
||||
; Clip a signed integer to an unsigned power of two range.
|
||||
; av_clip_uintp2
|
||||
; 1 - dest
|
||||
; 2 - bit position to clip at
|
||||
%macro CLIPP2 2
|
||||
; (~a) >> 31 & ((1<<p) - 1);
|
||||
pcmpeqb m4, m4
|
||||
pxor m4, %1
|
||||
psrad m4, 31
|
||||
movu m5, [pd_yuv2gbrp16_upper%2]
|
||||
pand m4, m5
|
||||
|
||||
; (a & ~((1<<p) - 1)) == 0
|
||||
pandn m5, %1
|
||||
pxor m6, m6
|
||||
pcmpeqd m5, m6
|
||||
%if cpuflag(avx2)
|
||||
vpblendvb %1, m4, %1, m5
|
||||
%else
|
||||
pxor %1, m4
|
||||
pand %1, m5
|
||||
pxor %1, m4
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; 1 - dest
|
||||
; 2 - source
|
||||
%macro LOAD16 2
|
||||
%if cpuflag(avx2)
|
||||
movu xm%1, %2
|
||||
vpmovsxwd m%1, xm%1
|
||||
%elif cpuflag(sse4)
|
||||
movsd m%1, %2
|
||||
pmovsxwd m%1, m%1
|
||||
%else
|
||||
movsd m%1, %2
|
||||
punpcklwd m%1, m%1
|
||||
psrad m%1, 16 ; sign extend
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; 1 - dest
|
||||
; 2 - source
|
||||
; 3 - depth
|
||||
%macro LOAD_PIXELS 3
|
||||
mov ptrq, [%2 + jq*8]
|
||||
%if %3 >= 16
|
||||
movu m%1, [ptrq + xq*4]
|
||||
%else
|
||||
LOAD16 %1, [ptrq + xq*2]
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; 1 - dest
|
||||
; 2 - source
|
||||
%macro STORE8 2
|
||||
mov ptrq, %1
|
||||
%if mmsize > 16
|
||||
pshufb m%2, [pb_pack_shuffle8]
|
||||
vextractf128 xm4, m%2, 1
|
||||
por xm%2, xm4
|
||||
movq [ptrq + xq], xm%2
|
||||
%else
|
||||
%if cpuflag(sse4)
|
||||
pshufb m%2, [pb_pack_shuffle8]
|
||||
%else
|
||||
psrldq m4, m%2, 3
|
||||
por m%2, m4
|
||||
psrldq m4, m%2, 6
|
||||
por m%2, m4
|
||||
%endif
|
||||
movd [ptrq + xq], m%2
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; 1 - dest
|
||||
; 2 - source
|
||||
; 3 - is big endian
|
||||
%macro STORE16 3
|
||||
mov ptrq, %1
|
||||
%if mmsize > 16
|
||||
%if %3 ; bigendian
|
||||
pshufb m%2, [pb_pack_shuffle16be]
|
||||
%else
|
||||
pshufb m%2, [pb_pack_shuffle16le]
|
||||
%endif
|
||||
vpermq m%2, m%2, (3 << 6 | 0 << 4 | 3 << 2 | 0 << 0)
|
||||
movu [ptrq + xq*2], xm%2
|
||||
%else
|
||||
%if cpuflag(sse4) && %3 ; bigendian
|
||||
pshufb m%2, [pb_pack_shuffle16be]
|
||||
%elif cpuflag(sse4)
|
||||
pshufb m%2, [pb_pack_shuffle16le]
|
||||
%else
|
||||
pshuflw m%2, m%2, (1 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
|
||||
pshufhw m%2, m%2, (1 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
|
||||
pshufd m%2, m%2, (3 << 6 | 3 << 4 | 2 << 2 | 0 << 0)
|
||||
%if %3 ; bigendian
|
||||
psrlw m4, m%2, 8
|
||||
psllw m%2, 8
|
||||
por m%2, m4
|
||||
%endif
|
||||
%endif
|
||||
movq [ptrq + xq*2], m%2
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%macro SWAP32 1
|
||||
%if mmsize > 16 || cpuflag(sse4)
|
||||
pshufb m%1, [pb_shuffle32be]
|
||||
%else
|
||||
psrlw m4, m%1, 8
|
||||
psllw m%1, 8
|
||||
por m%1, m4
|
||||
pshuflw m%1, m%1, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0)
|
||||
pshufhw m%1, m%1, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0)
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; 1 - dest
|
||||
; 2 - source
|
||||
; 3 - depth
|
||||
; 4 - is big endian
|
||||
%macro STORE_PIXELS 4
|
||||
%if %3 > 16
|
||||
%if %4
|
||||
SWAP32 %2
|
||||
%endif
|
||||
mov ptrq, %1
|
||||
movu [ptrq + xq*4], m%2
|
||||
%elif %3 > 8
|
||||
STORE16 %1, %2, %4
|
||||
%else
|
||||
STORE8 %1, %2
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%macro PMULLO 3
|
||||
%if cpuflag(sse4) || mmsize > 16
|
||||
pmulld %1, %2, %3
|
||||
%else
|
||||
%ifidni %1, %2
|
||||
%else
|
||||
mova %1, %2
|
||||
%endif
|
||||
pshufd m7, %1, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0) ; 0xb1
|
||||
pshufd m8, %3, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0) ; 0xb1
|
||||
pmuludq m7, m8
|
||||
pshufd m7, m7, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0) ; 0xd8
|
||||
pmuludq %1, %3
|
||||
pshufd %1, %1, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0) ; 0xd8
|
||||
punpckldq %1, m7
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
; 1 - name
|
||||
; 2 - depth
|
||||
; 3 - has alpha
|
||||
; 3 - is big endian
|
||||
; 5 - is float
|
||||
%macro yuv2gbrp_fn 5
|
||||
%define DEPTH %2
|
||||
%define HAS_ALPHA %3
|
||||
%define IS_BE %4
|
||||
%define FLOAT %5
|
||||
%define SH (22 + 8 - DEPTH)
|
||||
|
||||
%if DEPTH >= 16
|
||||
%define RGB_SHIFT 14
|
||||
%define A_SHIFT 14
|
||||
%elif 22 != SH
|
||||
%define RGB_SHIFT SH
|
||||
%define A_SHIFT (SH-3)
|
||||
%else
|
||||
%define RGB_SHIFT 22
|
||||
%define A_SHIFT 19
|
||||
%endif
|
||||
|
||||
%if DEPTH >= 16
|
||||
%define YUV_SHIFT 14
|
||||
%define Y_START m9
|
||||
%define Y_ROUND [pd_yuv2gbrp16_round13]
|
||||
%define UV_START m9
|
||||
%define A_START m9
|
||||
%define A_CLIP2P 30
|
||||
%else
|
||||
%define YUV_SHIFT 10
|
||||
%define Y_START [pd_yuv2gbrp_y_start]
|
||||
%define Y_ROUND m9
|
||||
%define UV_START [pd_yuv2gbrp_uv_start]
|
||||
%define A_START [pd_yuv2gbrp_a_start]
|
||||
%define A_CLIP2P 27
|
||||
%endif
|
||||
|
||||
cglobal yuv2%1_full_X, 12, 14, 16, ptr, lumFilter, lumSrcx, lumFilterSize, chrFilter, chrUSrcx, chrVSrcx, chrFilterSize, alpSrcx, dest, dstW, y, x, j
|
||||
VBROADCASTSS m10, dword [ptrq + SwsInternal.yuv2rgb_y_offset]
|
||||
VBROADCASTSS m11, dword [ptrq + SwsInternal.yuv2rgb_y_coeff]
|
||||
VBROADCASTSS m12, dword [ptrq + SwsInternal.yuv2rgb_v2r_coeff]
|
||||
VBROADCASTSS m13, dword [ptrq + SwsInternal.yuv2rgb_v2g_coeff]
|
||||
VBROADCASTSS m14, dword [ptrq + SwsInternal.yuv2rgb_u2g_coeff]
|
||||
VBROADCASTSS m15, dword [ptrq + SwsInternal.yuv2rgb_u2b_coeff]
|
||||
|
||||
%if DEPTH >= 16
|
||||
movu m9, [pd_yuv2gbrp16_start]
|
||||
%else
|
||||
mov xq, (1 << (SH-1))
|
||||
movq xm9, xq
|
||||
VBROADCASTSS m9, xm9
|
||||
%endif
|
||||
xor xq, xq
|
||||
|
||||
%%loop_x:
|
||||
movu Y, Y_START
|
||||
movu U, UV_START
|
||||
movu V, UV_START
|
||||
|
||||
xor jq, jq
|
||||
%%loop_luma:
|
||||
movsx ptrd, word [lumFilterq + jq*2]
|
||||
movd xm0, ptrd
|
||||
VBROADCASTSS m0, xm0
|
||||
LOAD_PIXELS 1, lumSrcxq, DEPTH
|
||||
PMULLO m1, m1, m0
|
||||
paddd Y, m1
|
||||
inc jd
|
||||
cmp jd, lumFilterSized
|
||||
jl %%loop_luma
|
||||
|
||||
%if HAS_ALPHA
|
||||
cmp alpSrcxq, 0
|
||||
je %%skip_alpha_load
|
||||
xor jq, jq
|
||||
movu A, A_START
|
||||
%%loop_alpha:
|
||||
movsx ptrd, word [lumFilterq + jq*2]
|
||||
movd xm0, ptrd
|
||||
VBROADCASTSS m0, xm0
|
||||
LOAD_PIXELS 1, alpSrcxq, DEPTH
|
||||
PMULLO m1, m1, m0
|
||||
paddd A, m1
|
||||
inc jd
|
||||
cmp jd, lumFilterSized
|
||||
jl %%loop_alpha
|
||||
%if DEPTH >= 16
|
||||
psrad A, 1
|
||||
paddd A, [pd_yuv2gbrp16_a_offset]
|
||||
%endif
|
||||
%%skip_alpha_load:
|
||||
%endif
|
||||
xor jq, jq
|
||||
%%loop_chr:
|
||||
movsx ptrd, word [chrFilterq + jq*2]
|
||||
movd xm0, ptrd
|
||||
VBROADCASTSS m0, xm0
|
||||
LOAD_PIXELS 1, chrUSrcxq, DEPTH
|
||||
LOAD_PIXELS 2, chrVSrcxq, DEPTH
|
||||
PMULLO m1, m1, m0
|
||||
PMULLO m2, m2, m0
|
||||
paddd U, m1
|
||||
paddd V, m2
|
||||
inc jd
|
||||
cmp jd, chrFilterSized
|
||||
jl %%loop_chr
|
||||
|
||||
psrad Y, YUV_SHIFT
|
||||
%if DEPTH >= 16
|
||||
paddd Y, [pd_yuv2gbrp16_offset]
|
||||
%endif
|
||||
psrad U, YUV_SHIFT
|
||||
psrad V, YUV_SHIFT
|
||||
|
||||
psubd Y, m10 ; yuv2rgb_y_offset
|
||||
PMULLO Y, Y, m11 ; yuv2rgb_y_coeff
|
||||
paddd Y, Y_ROUND
|
||||
|
||||
PMULLO R, V, m12 ; yuv2rgb_v2r_coeff
|
||||
PMULLO B, U, m15 ; yuv2rgb_u2b_coeff
|
||||
|
||||
PMULLO U, U, m14 ; yuv2rgb_u2g_coeff
|
||||
PMULLO V, V, m13 ; yuv2rgb_v2g_coeff
|
||||
paddd G, U, V
|
||||
paddd R, Y
|
||||
paddd G, Y
|
||||
paddd B, Y
|
||||
|
||||
%if DEPTH < 16
|
||||
CLIPP2 R, 30
|
||||
CLIPP2 G, 30
|
||||
CLIPP2 B, 30
|
||||
%endif
|
||||
|
||||
psrad R, RGB_SHIFT
|
||||
psrad G, RGB_SHIFT
|
||||
psrad B, RGB_SHIFT
|
||||
|
||||
%if DEPTH >= 16
|
||||
paddd R, [pd_yuv2gbrp_debias]
|
||||
paddd G, [pd_yuv2gbrp_debias]
|
||||
paddd B, [pd_yuv2gbrp_debias]
|
||||
|
||||
CLIPP2 R, 16
|
||||
CLIPP2 G, 16
|
||||
CLIPP2 B, 16
|
||||
%endif
|
||||
|
||||
%if FLOAT
|
||||
cvtdq2ps R, R
|
||||
cvtdq2ps G, G
|
||||
cvtdq2ps B, B
|
||||
mulps R, [pd_65535_invf]
|
||||
mulps G, [pd_65535_invf]
|
||||
mulps B, [pd_65535_invf]
|
||||
%endif
|
||||
STORE_PIXELS [destq + 0], 1, DEPTH, IS_BE ; G
|
||||
STORE_PIXELS [destq + 8], 2, DEPTH, IS_BE ; B
|
||||
STORE_PIXELS [destq + 16], 0, DEPTH, IS_BE ; R
|
||||
|
||||
%if HAS_ALPHA
|
||||
cmp alpSrcxq, 0
|
||||
je %%skip_alpha_store
|
||||
CLIPP2 A, A_CLIP2P
|
||||
psrad A, A_SHIFT
|
||||
%if FLOAT
|
||||
cvtdq2ps A, A
|
||||
mulps A, [pd_65535_invf]
|
||||
%endif
|
||||
STORE_PIXELS [destq + 24], 3, DEPTH, IS_BE
|
||||
%%skip_alpha_store:
|
||||
%endif
|
||||
add xq, mmsize/4
|
||||
cmp xd, dstWd
|
||||
jl %%loop_x
|
||||
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
%macro yuv2gbrp_fn_decl 2
|
||||
INIT_%1 %2
|
||||
yuv2gbrp_fn gbrp, 8, 0, 0, 0
|
||||
yuv2gbrp_fn gbrap, 8, 1, 0, 0
|
||||
yuv2gbrp_fn gbrp9le, 9, 0, 0, 0
|
||||
yuv2gbrp_fn gbrp10le, 10, 0, 0, 0
|
||||
yuv2gbrp_fn gbrap10le, 10, 1, 0, 0
|
||||
yuv2gbrp_fn gbrp12le, 12, 0, 0, 0
|
||||
yuv2gbrp_fn gbrap12le, 12, 1, 0, 0
|
||||
yuv2gbrp_fn gbrp14le, 14, 0, 0, 0
|
||||
yuv2gbrp_fn gbrp16le, 16, 0, 0, 0
|
||||
yuv2gbrp_fn gbrap16le, 16, 1, 0, 0
|
||||
yuv2gbrp_fn gbrpf32le, 32, 0, 0, 1
|
||||
yuv2gbrp_fn gbrapf32le, 32, 1, 0, 1
|
||||
|
||||
yuv2gbrp_fn gbrp9be, 9, 0, 1, 0
|
||||
yuv2gbrp_fn gbrp10be, 10, 0, 1, 0
|
||||
yuv2gbrp_fn gbrap10be, 10, 1, 1, 0
|
||||
yuv2gbrp_fn gbrp12be, 12, 0, 1, 0
|
||||
yuv2gbrp_fn gbrap12be, 12, 1, 1, 0
|
||||
yuv2gbrp_fn gbrp14be, 14, 0, 1, 0
|
||||
yuv2gbrp_fn gbrp16be, 16, 0, 1, 0
|
||||
yuv2gbrp_fn gbrap16be, 16, 1, 1, 0
|
||||
yuv2gbrp_fn gbrpf32be, 32, 0, 1, 1
|
||||
yuv2gbrp_fn gbrapf32be, 32, 1, 1, 1
|
||||
%endmacro
|
||||
|
||||
yuv2gbrp_fn_decl XMM, sse2
|
||||
yuv2gbrp_fn_decl XMM, sse4
|
||||
|
||||
%if HAVE_AVX2_EXTERNAL
|
||||
yuv2gbrp_fn_decl YMM, avx2
|
||||
%endif
|
||||
|
||||
%endif ; ARCH_X86_64
|
||||
@@ -0,0 +1,201 @@
|
||||
;******************************************************************************
|
||||
;* Copyright (c) 2024 Ramiro Polla
|
||||
;*
|
||||
;* 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_RODATA
|
||||
pack19: times 4 dd (1 << 19) - 1
|
||||
|
||||
SECTION .text
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; lumConvertRange
|
||||
;
|
||||
; void ff_lumRangeToJpeg{8,16}_<opt>(int16_t *dst, int width,
|
||||
; uint32_t coeff, int64_t offset);
|
||||
; void ff_lumRangeFromJpeg{8,16}_<opt>(int16_t *dst, int width,
|
||||
; uint32_t coeff, int64_t offset);
|
||||
;
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
%macro LUMCONVERTRANGE 2
|
||||
cglobal lumRange%1Jpeg%2, 4, 4, 5, dst, width, coeff, offset
|
||||
shl widthd, %2 >> 3
|
||||
movd xm2, coeffd
|
||||
VBROADCASTSS m2, xm2
|
||||
%if ARCH_X86_64
|
||||
movq xm3, offsetq
|
||||
%else
|
||||
movq xm3, offsetm
|
||||
%endif
|
||||
%if %2 == 16
|
||||
VBROADCASTSD m3, xm3
|
||||
%ifidni %1,To
|
||||
VBROADCASTI128 m4, [pack19]
|
||||
%endif
|
||||
%elif %2 == 8
|
||||
VBROADCASTSS m3, xm3
|
||||
pxor m4, m4
|
||||
%endif ; %2 == 8/16
|
||||
add dstq, widthq
|
||||
neg widthq
|
||||
.loop:
|
||||
movu m0, [dstq+widthq]
|
||||
%if %2 == 16
|
||||
pshufd m1, m0, 0xb1
|
||||
pmuldq m0, m2
|
||||
pmuldq m1, m2
|
||||
paddq m0, m3
|
||||
paddq m1, m3
|
||||
psrlq m0, 18
|
||||
psrlq m1, 18
|
||||
pshufd m0, m0, 0xd8
|
||||
pshufd m1, m1, 0xd8
|
||||
punpckldq m0, m1
|
||||
%ifidni %1,To
|
||||
PMINSD m0, m4, m1
|
||||
%endif
|
||||
%elif %2 == 8
|
||||
punpckhwd m1, m0, m4
|
||||
punpcklwd m0, m4
|
||||
pmaddwd m0, m2
|
||||
pmaddwd m1, m2
|
||||
paddd m0, m3
|
||||
paddd m1, m3
|
||||
psrad m0, 14
|
||||
psrad m1, 14
|
||||
packssdw m0, m1
|
||||
%endif ; %2 == 8/16
|
||||
movu [dstq+widthq], m0
|
||||
add widthq, mmsize
|
||||
jl .loop
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; chrConvertRange
|
||||
;
|
||||
; void ff_chrRangeToJpeg{8,16}_<opt>(int16_t *dstU, int16_t *dstV, int width,
|
||||
; uint32_t coeff, int64_t offset);
|
||||
; void ff_chrRangeFromJpeg{8,16}_<opt>(int16_t *dstU, int16_t *dstV, int width,
|
||||
; uint32_t coeff, int64_t offset);
|
||||
;
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
%macro CHRCONVERTRANGE 2
|
||||
cglobal chrRange%1Jpeg%2, 5, 5, 7, dstU, dstV, width, coeff, offset
|
||||
shl widthd, %2 >> 3
|
||||
movd xm4, coeffd
|
||||
VBROADCASTSS m4, xm4
|
||||
%if ARCH_X86_64
|
||||
movq xm5, offsetq
|
||||
%else
|
||||
movq xm5, offsetm
|
||||
%endif
|
||||
%if %2 == 16
|
||||
VBROADCASTSD m5, xm5
|
||||
%ifidni %1,To
|
||||
VBROADCASTI128 m6, [pack19]
|
||||
%endif
|
||||
%elif %2 == 8
|
||||
VBROADCASTSS m5, xm5
|
||||
pxor m6, m6
|
||||
%endif ; %2 == 8/16
|
||||
add dstUq, widthq
|
||||
add dstVq, widthq
|
||||
neg widthq
|
||||
.loop:
|
||||
movu m0, [dstUq+widthq]
|
||||
movu m2, [dstVq+widthq]
|
||||
%if %2 == 16
|
||||
pshufd m1, m0, 0xb1
|
||||
pshufd m3, m2, 0xb1
|
||||
pmuldq m0, m4
|
||||
pmuldq m1, m4
|
||||
pmuldq m2, m4
|
||||
pmuldq m3, m4
|
||||
paddq m0, m5
|
||||
paddq m1, m5
|
||||
paddq m2, m5
|
||||
paddq m3, m5
|
||||
psrlq m0, 18
|
||||
psrlq m1, 18
|
||||
psrlq m2, 18
|
||||
psrlq m3, 18
|
||||
pshufd m0, m0, 0xd8
|
||||
pshufd m1, m1, 0xd8
|
||||
pshufd m2, m2, 0xd8
|
||||
pshufd m3, m3, 0xd8
|
||||
punpckldq m0, m1
|
||||
punpckldq m2, m3
|
||||
%ifidni %1,To
|
||||
PMINSD m0, m6, m1
|
||||
PMINSD m2, m6, m3
|
||||
%endif
|
||||
%elif %2 == 8
|
||||
punpckhwd m1, m0, m6
|
||||
punpckhwd m3, m2, m6
|
||||
punpcklwd m0, m6
|
||||
punpcklwd m2, m6
|
||||
pmaddwd m0, m4
|
||||
pmaddwd m1, m4
|
||||
pmaddwd m2, m4
|
||||
pmaddwd m3, m4
|
||||
paddd m0, m5
|
||||
paddd m1, m5
|
||||
paddd m2, m5
|
||||
paddd m3, m5
|
||||
psrad m0, 14
|
||||
psrad m1, 14
|
||||
psrad m2, 14
|
||||
psrad m3, 14
|
||||
packssdw m0, m1
|
||||
packssdw m2, m3
|
||||
%endif ; %2 == 8/16
|
||||
movu [dstUq+widthq], m0
|
||||
movu [dstVq+widthq], m2
|
||||
add widthq, mmsize
|
||||
jl .loop
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
LUMCONVERTRANGE To, 8
|
||||
CHRCONVERTRANGE To, 8
|
||||
LUMCONVERTRANGE From, 8
|
||||
CHRCONVERTRANGE From, 8
|
||||
|
||||
INIT_XMM sse4
|
||||
LUMCONVERTRANGE To, 16
|
||||
CHRCONVERTRANGE To, 16
|
||||
LUMCONVERTRANGE From, 16
|
||||
CHRCONVERTRANGE From, 16
|
||||
|
||||
%if HAVE_AVX2_EXTERNAL
|
||||
INIT_YMM avx2
|
||||
LUMCONVERTRANGE To, 8
|
||||
LUMCONVERTRANGE To, 16
|
||||
CHRCONVERTRANGE To, 8
|
||||
CHRCONVERTRANGE To, 16
|
||||
LUMCONVERTRANGE From, 8
|
||||
LUMCONVERTRANGE From, 16
|
||||
CHRCONVERTRANGE From, 8
|
||||
CHRCONVERTRANGE From, 16
|
||||
%endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,411 @@
|
||||
;******************************************************************************
|
||||
;* Copyright Nick Kurshev
|
||||
;* Copyright Michael (michaelni@gmx.at)
|
||||
;* Copyright 2018 Jokyo Images
|
||||
;* Copyright Ivo van Poorten
|
||||
;*
|
||||
;* 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_RODATA
|
||||
|
||||
pb_shuffle2103: db 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15
|
||||
pb_shuffle0321: db 0, 3, 2, 1, 4, 7, 6, 5, 8, 11, 10, 9, 12, 15, 14, 13
|
||||
pb_shuffle1230: db 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12
|
||||
pb_shuffle3012: db 3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, 12, 13, 14
|
||||
pb_shuffle3210: db 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
|
||||
pb_shuffle3102: db 3, 1, 0, 2, 7, 5, 4, 6, 11, 9, 8, 10, 15, 13, 12, 14
|
||||
pb_shuffle2013: db 2, 0, 1, 3, 6, 4, 5, 7, 10, 8, 9, 11, 14, 12, 13, 15
|
||||
pb_shuffle2130: db 2, 1, 3, 0, 6, 5, 7, 4, 10, 9, 11, 8, 14, 13, 15, 12
|
||||
pb_shuffle1203: db 1, 2, 0, 3, 5, 6, 4, 7, 9, 10, 8, 11, 13, 14, 12, 15
|
||||
|
||||
%if HAVE_AVX512ICL_EXTERNAL
|
||||
; shuffle vector to rearrange packuswb result to be linear
|
||||
shuf_packus: db 0, 1, 2, 3, 16, 17, 18, 19, 32, 33, 34, 35, 48, 49, 50, 51,\
|
||||
4, 5, 6, 7, 20, 21, 22, 23, 36, 37, 38, 39, 52, 53, 54, 55,\
|
||||
8, 9, 10, 11, 24, 25, 26, 27, 40, 41, 42, 43, 56, 57, 58, 59,\
|
||||
12, 13, 14, 15, 28, 29, 30, 31, 44, 45, 46, 47, 60, 61, 62, 63
|
||||
|
||||
; shuffle vector to combine odd elements from two vectors to extract Y
|
||||
shuf_perm2b: db 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,\
|
||||
33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,\
|
||||
65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,\
|
||||
97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127
|
||||
%endif
|
||||
|
||||
%if HAVE_AVX2_EXTERNAL
|
||||
; shuffle vector to rearrange packuswb result to be linear
|
||||
shuf_packus_avx2: db 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0,\
|
||||
2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0,
|
||||
%endif
|
||||
|
||||
SECTION .text
|
||||
|
||||
%macro RSHIFT_COPY 3
|
||||
; %1 dst ; %2 src ; %3 shift
|
||||
%if cpuflag(avx) || cpuflag(avx2) || cpuflag(avx512icl)
|
||||
psrldq %1, %2, %3
|
||||
%else
|
||||
mova %1, %2
|
||||
RSHIFT %1, %3
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; shuffle_bytes_## (const uint8_t *src, uint8_t *dst, int src_size)
|
||||
;------------------------------------------------------------------------------
|
||||
; %1-4 index shuffle
|
||||
%macro SHUFFLE_BYTES 4
|
||||
cglobal shuffle_bytes_%1%2%3%4, 3, 5, 2, src, dst, w, tmp, x
|
||||
VBROADCASTI128 m0, [pb_shuffle%1%2%3%4]
|
||||
movsxdifnidn wq, wd
|
||||
mov xq, wq
|
||||
|
||||
add srcq, wq
|
||||
add dstq, wq
|
||||
neg wq
|
||||
|
||||
%if mmsize == 64
|
||||
and xq, mmsize - 4
|
||||
shr xq, 2
|
||||
mov tmpd, -1
|
||||
shlx tmpd, tmpd, xd
|
||||
not tmpd
|
||||
kmovw k7, tmpd
|
||||
vmovdqu32 m1{k7}{z}, [srcq + wq]
|
||||
pshufb m1, m0
|
||||
vmovdqu32 [dstq + wq]{k7}, m1
|
||||
lea wq, [wq + 4 * xq]
|
||||
%else
|
||||
;calc scalar loop
|
||||
and xq, mmsize-4
|
||||
je .loop_simd
|
||||
|
||||
.loop_scalar:
|
||||
mov tmpb, [srcq + wq + %1]
|
||||
mov [dstq+wq + 0], tmpb
|
||||
mov tmpb, [srcq + wq + %2]
|
||||
mov [dstq+wq + 1], tmpb
|
||||
mov tmpb, [srcq + wq + %3]
|
||||
mov [dstq+wq + 2], tmpb
|
||||
mov tmpb, [srcq + wq + %4]
|
||||
mov [dstq+wq + 3], tmpb
|
||||
add wq, 4
|
||||
sub xq, 4
|
||||
jg .loop_scalar
|
||||
%endif
|
||||
|
||||
;check if src_size < mmsize
|
||||
cmp wq, 0
|
||||
jge .end
|
||||
|
||||
.loop_simd:
|
||||
movu m1, [srcq + wq]
|
||||
pshufb m1, m0
|
||||
movu [dstq + wq], m1
|
||||
add wq, mmsize
|
||||
jl .loop_simd
|
||||
|
||||
.end:
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_XMM ssse3
|
||||
SHUFFLE_BYTES 2, 1, 0, 3
|
||||
SHUFFLE_BYTES 0, 3, 2, 1
|
||||
SHUFFLE_BYTES 1, 2, 3, 0
|
||||
SHUFFLE_BYTES 3, 0, 1, 2
|
||||
SHUFFLE_BYTES 3, 2, 1, 0
|
||||
SHUFFLE_BYTES 3, 1, 0, 2
|
||||
SHUFFLE_BYTES 2, 0, 1, 3
|
||||
SHUFFLE_BYTES 2, 1, 3, 0
|
||||
SHUFFLE_BYTES 1, 2, 0, 3
|
||||
|
||||
%if ARCH_X86_64
|
||||
%if HAVE_AVX2_EXTERNAL
|
||||
INIT_YMM avx2
|
||||
SHUFFLE_BYTES 2, 1, 0, 3
|
||||
SHUFFLE_BYTES 0, 3, 2, 1
|
||||
SHUFFLE_BYTES 1, 2, 3, 0
|
||||
SHUFFLE_BYTES 3, 0, 1, 2
|
||||
SHUFFLE_BYTES 3, 2, 1, 0
|
||||
SHUFFLE_BYTES 3, 1, 0, 2
|
||||
SHUFFLE_BYTES 2, 0, 1, 3
|
||||
SHUFFLE_BYTES 2, 1, 3, 0
|
||||
SHUFFLE_BYTES 1, 2, 0, 3
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if ARCH_X86_64
|
||||
%if HAVE_AVX512ICL_EXTERNAL
|
||||
INIT_ZMM avx512icl
|
||||
SHUFFLE_BYTES 2, 1, 0, 3
|
||||
SHUFFLE_BYTES 0, 3, 2, 1
|
||||
SHUFFLE_BYTES 1, 2, 3, 0
|
||||
SHUFFLE_BYTES 3, 0, 1, 2
|
||||
SHUFFLE_BYTES 3, 2, 1, 0
|
||||
SHUFFLE_BYTES 3, 1, 0, 2
|
||||
SHUFFLE_BYTES 2, 0, 1, 3
|
||||
SHUFFLE_BYTES 2, 1, 3, 0
|
||||
SHUFFLE_BYTES 1, 2, 0, 3
|
||||
%endif
|
||||
%endif
|
||||
|
||||
;-----------------------------------------------------------------------------------------------
|
||||
; uyvytoyuv422(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
|
||||
; const uint8_t *src, int width, int height,
|
||||
; int lumStride, int chromStride, int srcStride)
|
||||
;-----------------------------------------------------------------------------------------------
|
||||
%macro UYVY_TO_YUV422 0
|
||||
cglobal uyvytoyuv422, 9, 14, 8 + cpuflag(avx2) + cpuflag(avx512icl), ydst, udst, vdst, src, w, h, lum_stride, chrom_stride, src_stride, wtwo, whalf, tmp, x, back_w
|
||||
pxor m0, m0
|
||||
%if mmsize == 64
|
||||
vpternlogd m1, m1, m1, 0xff ; m1 = _mm512_set1_epi8(0xff)
|
||||
movu m8, [shuf_packus]
|
||||
movu m9, [shuf_perm2b]
|
||||
%else
|
||||
%if cpuflag(avx2)
|
||||
movu m8, [shuf_packus_avx2]
|
||||
%endif
|
||||
pcmpeqw m1, m1
|
||||
%endif
|
||||
psrlw m1, 8
|
||||
|
||||
movsxdifnidn wq, wd
|
||||
movsxdifnidn lum_strideq, lum_strided
|
||||
movsxdifnidn chrom_strideq, chrom_strided
|
||||
movsxdifnidn src_strideq, src_strided
|
||||
|
||||
mov back_wq, wq
|
||||
mov whalfq, wq
|
||||
shr whalfq, 1 ; whalf = width / 2
|
||||
|
||||
lea srcq, [srcq + wq * 2]
|
||||
add ydstq, wq
|
||||
add udstq, whalfq
|
||||
add vdstq, whalfq
|
||||
|
||||
.loop_line:
|
||||
mov xq, wq
|
||||
mov wtwoq, wq
|
||||
add wtwoq, wtwoq ; wtwo = width * 2
|
||||
|
||||
neg wq
|
||||
neg wtwoq
|
||||
neg whalfq
|
||||
|
||||
;calc scalar loop count
|
||||
and xq, mmsize * 2 - 1
|
||||
je .loop_simd
|
||||
|
||||
%if mmsize == 64
|
||||
shr xq, 1
|
||||
mov tmpq, -1
|
||||
shlx tmpq, tmpq, xq
|
||||
not tmpq
|
||||
kmovq k7, tmpq ; write mask for U/V
|
||||
kmovd k1, tmpd ; write mask for 1st half of Y
|
||||
kmovw k3, tmpd ; read mask for 1st vector
|
||||
shr tmpq, 16
|
||||
kmovw k4, tmpd ; read mask for 2nd vector
|
||||
shr tmpq, 16
|
||||
kmovd k2, tmpd ; write mask for 2nd half of Y
|
||||
kmovw k5, tmpd ; read mask for 3rd vector
|
||||
shr tmpd, 16
|
||||
kmovw k6, tmpd ; read mask for 4th vector
|
||||
|
||||
vmovdqu32 m2{k3}{z}, [srcq + wtwoq ]
|
||||
vmovdqu32 m3{k4}{z}, [srcq + wtwoq + mmsize ]
|
||||
vmovdqu32 m4{k5}{z}, [srcq + wtwoq + mmsize * 2]
|
||||
vmovdqu32 m5{k6}{z}, [srcq + wtwoq + mmsize * 3]
|
||||
|
||||
; extract y part 1
|
||||
mova m6, m9
|
||||
vpermi2b m6, m2, m3 ; UYVY UYVY -> YYYY using permute
|
||||
vmovdqu16 [ydstq + wq]{k1}, m6
|
||||
|
||||
; extract y part 2
|
||||
mova m7, m9
|
||||
vpermi2b m7, m4, m5 ; UYVY UYVY -> YYYY using permute
|
||||
vmovdqu16 [ydstq + wq + mmsize]{k2}, m7
|
||||
|
||||
; extract uv
|
||||
pand m2, m1 ; UxVx...
|
||||
pand m3, m1 ; UxVx...
|
||||
pand m4, m1 ; UxVx...
|
||||
pand m5, m1 ; UxVx...
|
||||
packuswb m2, m3 ; UVUV...
|
||||
packuswb m4, m5 ; UVUV...
|
||||
|
||||
; U
|
||||
pand m6, m2, m1 ; UxUx...
|
||||
pand m7, m4, m1 ; UxUx...
|
||||
packuswb m6, m7 ; UUUU
|
||||
vpermb m6, m8, m6
|
||||
vmovdqu8 [udstq + whalfq]{k7}, m6
|
||||
|
||||
; V
|
||||
psrlw m2, 8 ; VxVx...
|
||||
psrlw m4, 8 ; VxVx...
|
||||
packuswb m2, m4 ; VVVV
|
||||
vpermb m2, m8, m2
|
||||
vmovdqu8 [vdstq + whalfq]{k7}, m2
|
||||
|
||||
lea wq, [ wq + 2 * xq]
|
||||
lea wtwoq, [wtwoq + 4 * xq]
|
||||
add whalfq, xq
|
||||
%else
|
||||
.loop_scalar:
|
||||
mov tmpb, [srcq + wtwoq + 0]
|
||||
mov [udstq + whalfq], tmpb
|
||||
|
||||
mov tmpb, [srcq + wtwoq + 1]
|
||||
mov [ydstq + wq], tmpb
|
||||
|
||||
mov tmpb, [srcq + wtwoq + 2]
|
||||
mov [vdstq + whalfq], tmpb
|
||||
|
||||
mov tmpb, [srcq + wtwoq + 3]
|
||||
mov [ydstq + wq + 1], tmpb
|
||||
|
||||
add wq, 2
|
||||
add wtwoq, 4
|
||||
add whalfq, 1
|
||||
sub xq, 2
|
||||
jg .loop_scalar
|
||||
%endif
|
||||
|
||||
; check if simd loop is need
|
||||
cmp wq, 0
|
||||
jge .end_line
|
||||
|
||||
.loop_simd:
|
||||
movu m2, [srcq + wtwoq ]
|
||||
movu m3, [srcq + wtwoq + mmsize ]
|
||||
movu m4, [srcq + wtwoq + mmsize * 2]
|
||||
movu m5, [srcq + wtwoq + mmsize * 3]
|
||||
|
||||
%if mmsize == 64
|
||||
; extract y part 1
|
||||
mova m6, m9
|
||||
vpermi2b m6, m2, m3 ; UYVY UYVY -> YYYY using permute
|
||||
movu [ydstq + wq], m6
|
||||
|
||||
; extract y part 2
|
||||
mova m7, m9
|
||||
vpermi2b m7, m4, m5 ; UYVY UYVY -> YYYY using permute
|
||||
movu [ydstq + wq + mmsize], m7
|
||||
%else
|
||||
; extract y part 1
|
||||
RSHIFT_COPY m6, m2, 1 ; UYVY UYVY -> YVYU YVY...
|
||||
pand m6, m1 ; YxYx YxYx...
|
||||
|
||||
RSHIFT_COPY m7, m3, 1 ; UYVY UYVY -> YVYU YVY...
|
||||
pand m7, m1 ; YxYx YxYx...
|
||||
|
||||
packuswb m6, m7 ; YYYY YYYY...
|
||||
%if mmsize == 32
|
||||
vpermq m6, m6, 0xd8
|
||||
%endif
|
||||
movu [ydstq + wq], m6
|
||||
|
||||
; extract y part 2
|
||||
RSHIFT_COPY m6, m4, 1 ; UYVY UYVY -> YVYU YVY...
|
||||
pand m6, m1 ; YxYx YxYx...
|
||||
|
||||
RSHIFT_COPY m7, m5, 1 ; UYVY UYVY -> YVYU YVY...
|
||||
pand m7, m1 ; YxYx YxYx...
|
||||
|
||||
packuswb m6, m7 ; YYYY YYYY...
|
||||
%if mmsize == 32
|
||||
vpermq m6, m6, 0xd8
|
||||
%endif
|
||||
movu [ydstq + wq + mmsize], m6
|
||||
%endif
|
||||
|
||||
; extract uv
|
||||
pand m2, m1 ; UxVx...
|
||||
pand m3, m1 ; UxVx...
|
||||
pand m4, m1 ; UxVx...
|
||||
pand m5, m1 ; UxVx...
|
||||
|
||||
packuswb m2, m3 ; UVUV...
|
||||
packuswb m4, m5 ; UVUV...
|
||||
|
||||
; U
|
||||
pand m6, m2, m1 ; UxUx...
|
||||
pand m7, m4, m1 ; UxUx...
|
||||
|
||||
packuswb m6, m7 ; UUUU
|
||||
%if mmsize == 64
|
||||
vpermb m6, m8, m6
|
||||
%elif mmsize == 32
|
||||
vpermd m6, m8, m6
|
||||
%endif
|
||||
movu [udstq + whalfq], m6
|
||||
|
||||
|
||||
; V
|
||||
psrlw m2, 8 ; VxVx...
|
||||
psrlw m4, 8 ; VxVx...
|
||||
packuswb m2, m4 ; VVVV
|
||||
%if mmsize == 64
|
||||
vpermb m2, m8, m2
|
||||
%elif mmsize == 32
|
||||
vpermd m2, m8, m2
|
||||
%endif
|
||||
movu [vdstq + whalfq], m2
|
||||
|
||||
add whalfq, mmsize
|
||||
add wtwoq, mmsize * 4
|
||||
add wq, mmsize * 2
|
||||
jl .loop_simd
|
||||
|
||||
.end_line:
|
||||
add srcq, src_strideq
|
||||
add ydstq, lum_strideq
|
||||
add udstq, chrom_strideq
|
||||
add vdstq, chrom_strideq
|
||||
|
||||
;restore initial state of line variable
|
||||
mov wq, back_wq
|
||||
mov xq, wq
|
||||
mov whalfq, wq
|
||||
shr whalfq, 1 ; whalf = width / 2
|
||||
sub hd, 1
|
||||
jg .loop_line
|
||||
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
%if ARCH_X86_64
|
||||
INIT_XMM sse2
|
||||
UYVY_TO_YUV422
|
||||
|
||||
INIT_XMM avx
|
||||
UYVY_TO_YUV422
|
||||
%if HAVE_AVX2_EXTERNAL
|
||||
INIT_YMM avx2
|
||||
UYVY_TO_YUV422
|
||||
%endif
|
||||
%if HAVE_AVX512ICL_EXTERNAL
|
||||
INIT_ZMM avx512icl
|
||||
UYVY_TO_YUV422
|
||||
%endif
|
||||
%endif
|
||||
@@ -0,0 +1,389 @@
|
||||
;******************************************************************************
|
||||
;* x86-optimized horizontal line scaling functions
|
||||
;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@gmail.com>
|
||||
;*
|
||||
;* 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_RODATA
|
||||
|
||||
max_19bit_int: times 4 dd 0x7ffff
|
||||
minshort: times 8 dw 0x8000
|
||||
unicoeff: times 4 dd 0x20000000
|
||||
|
||||
SECTION .text
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; horizontal line scaling
|
||||
;
|
||||
; void hscale<source_width>to<intermediate_nbits>_<filterSize>_<opt>
|
||||
; (SwsInternal *c, int{16,32}_t *dst,
|
||||
; int dstW, const uint{8,16}_t *src,
|
||||
; const int16_t *filter,
|
||||
; const int32_t *filterPos, int filterSize);
|
||||
;
|
||||
; Scale one horizontal line. Input is either 8-bit width or 16-bit width
|
||||
; ($source_width can be either 8, 9, 10 or 16, difference is whether we have to
|
||||
; downscale before multiplying). Filter is 14 bits. Output is either 15 bits
|
||||
; (in int16_t) or 19 bits (in int32_t), as given in $intermediate_nbits. Each
|
||||
; output pixel is generated from $filterSize input pixels, the position of
|
||||
; the first pixel is given in filterPos[nOutputPixel].
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
; SCALE_FUNC source_width, intermediate_nbits, filtersize, filtersuffix, n_args, n_xmm
|
||||
%macro SCALE_FUNC 6
|
||||
%ifnidn %3, X
|
||||
cglobal hscale%1to%2_%4, %5, 7, %6, pos0, dst, w, src, filter, fltpos, pos1
|
||||
%else
|
||||
cglobal hscale%1to%2_%4, %5, 10, %6, pos0, dst, w, srcmem, filter, fltpos, fltsize
|
||||
%endif
|
||||
%if ARCH_X86_64
|
||||
movsxd wq, wd
|
||||
%define mov32 movsxd
|
||||
%else ; x86-32
|
||||
%define mov32 mov
|
||||
%endif ; x86-64
|
||||
%if %2 == 19
|
||||
mova m2, [max_19bit_int]
|
||||
%endif ; %2 == 19
|
||||
%if %1 == 16
|
||||
mova m6, [minshort]
|
||||
mova m7, [unicoeff]
|
||||
%elif %1 == 8
|
||||
pxor m3, m3
|
||||
%endif ; %1 == 8/16
|
||||
|
||||
%if %1 == 8
|
||||
%define movlh movd
|
||||
%define movbh movh
|
||||
%define srcmul 1
|
||||
%else ; %1 == 9-16
|
||||
%define movlh movq
|
||||
%define movbh movu
|
||||
%define srcmul 2
|
||||
%endif ; %1 == 8/9-16
|
||||
|
||||
%ifnidn %3, X
|
||||
|
||||
; setup loop
|
||||
%if %3 == 8
|
||||
shl wq, 1 ; this allows *16 (i.e. now *8) in lea instructions for the 8-tap filter
|
||||
%define wshr 1
|
||||
%else ; %3 == 4
|
||||
%define wshr 0
|
||||
%endif ; %3 == 8
|
||||
lea filterq, [filterq+wq*8]
|
||||
%if %2 == 15
|
||||
lea dstq, [dstq+wq*(2>>wshr)]
|
||||
%else ; %2 == 19
|
||||
lea dstq, [dstq+wq*(4>>wshr)]
|
||||
%endif ; %2 == 15/19
|
||||
lea fltposq, [fltposq+wq*(4>>wshr)]
|
||||
neg wq
|
||||
|
||||
.loop:
|
||||
%if %3 == 4 ; filterSize == 4 scaling
|
||||
; load 2x4 or 4x4 source pixels into m0/m1
|
||||
mov32 pos0q, dword [fltposq+wq*4+ 0] ; filterPos[0]
|
||||
mov32 pos1q, dword [fltposq+wq*4+ 4] ; filterPos[1]
|
||||
movlh m0, [srcq+pos0q*srcmul] ; src[filterPos[0] + {0,1,2,3}]
|
||||
%if mmsize == 8
|
||||
movlh m1, [srcq+pos1q*srcmul] ; src[filterPos[1] + {0,1,2,3}]
|
||||
%else ; mmsize == 16
|
||||
%if %1 > 8
|
||||
movhps m0, [srcq+pos1q*srcmul] ; src[filterPos[1] + {0,1,2,3}]
|
||||
%else ; %1 == 8
|
||||
movd m4, [srcq+pos1q*srcmul] ; src[filterPos[1] + {0,1,2,3}]
|
||||
%endif
|
||||
mov32 pos0q, dword [fltposq+wq*4+ 8] ; filterPos[2]
|
||||
mov32 pos1q, dword [fltposq+wq*4+12] ; filterPos[3]
|
||||
movlh m1, [srcq+pos0q*srcmul] ; src[filterPos[2] + {0,1,2,3}]
|
||||
%if %1 > 8
|
||||
movhps m1, [srcq+pos1q*srcmul] ; src[filterPos[3] + {0,1,2,3}]
|
||||
%else ; %1 == 8
|
||||
movd m5, [srcq+pos1q*srcmul] ; src[filterPos[3] + {0,1,2,3}]
|
||||
punpckldq m0, m4
|
||||
punpckldq m1, m5
|
||||
%endif ; %1 == 8
|
||||
%endif ; mmsize == 8/16
|
||||
%if %1 == 8
|
||||
punpcklbw m0, m3 ; byte -> word
|
||||
punpcklbw m1, m3 ; byte -> word
|
||||
%endif ; %1 == 8
|
||||
|
||||
; multiply with filter coefficients
|
||||
%if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
|
||||
; add back 0x8000 * sum(coeffs) after the horizontal add
|
||||
psubw m0, m6
|
||||
psubw m1, m6
|
||||
%endif ; %1 == 16
|
||||
pmaddwd m0, [filterq+wq*8+mmsize*0] ; *= filter[{0,1,..,6,7}]
|
||||
pmaddwd m1, [filterq+wq*8+mmsize*1] ; *= filter[{8,9,..,14,15}]
|
||||
|
||||
; add up horizontally (4 srcpix * 4 coefficients -> 1 dstpix)
|
||||
%if notcpuflag(ssse3) ; sse2
|
||||
mova m4, m0
|
||||
shufps m0, m1, 10001000b
|
||||
shufps m4, m1, 11011101b
|
||||
paddd m0, m4
|
||||
%else ; ssse3/sse4
|
||||
phaddd m0, m1 ; filter[{ 0, 1, 2, 3}]*src[filterPos[0]+{0,1,2,3}],
|
||||
; filter[{ 4, 5, 6, 7}]*src[filterPos[1]+{0,1,2,3}],
|
||||
; filter[{ 8, 9,10,11}]*src[filterPos[2]+{0,1,2,3}],
|
||||
; filter[{12,13,14,15}]*src[filterPos[3]+{0,1,2,3}]
|
||||
%endif ; sse2/ssse3/sse4
|
||||
%else ; %3 == 8, i.e. filterSize == 8 scaling
|
||||
; load 2x8 or 4x8 source pixels into m0, m1, m4 and m5
|
||||
mov32 pos0q, dword [fltposq+wq*2+0] ; filterPos[0]
|
||||
mov32 pos1q, dword [fltposq+wq*2+4] ; filterPos[1]
|
||||
movbh m0, [srcq+ pos0q *srcmul] ; src[filterPos[0] + {0,1,2,3,4,5,6,7}]
|
||||
%if mmsize == 8
|
||||
movbh m1, [srcq+(pos0q+4)*srcmul] ; src[filterPos[0] + {4,5,6,7}]
|
||||
movbh m4, [srcq+ pos1q *srcmul] ; src[filterPos[1] + {0,1,2,3}]
|
||||
movbh m5, [srcq+(pos1q+4)*srcmul] ; src[filterPos[1] + {4,5,6,7}]
|
||||
%else ; mmsize == 16
|
||||
movbh m1, [srcq+ pos1q *srcmul] ; src[filterPos[1] + {0,1,2,3,4,5,6,7}]
|
||||
mov32 pos0q, dword [fltposq+wq*2+8] ; filterPos[2]
|
||||
mov32 pos1q, dword [fltposq+wq*2+12] ; filterPos[3]
|
||||
movbh m4, [srcq+ pos0q *srcmul] ; src[filterPos[2] + {0,1,2,3,4,5,6,7}]
|
||||
movbh m5, [srcq+ pos1q *srcmul] ; src[filterPos[3] + {0,1,2,3,4,5,6,7}]
|
||||
%endif ; mmsize == 8/16
|
||||
%if %1 == 8
|
||||
punpcklbw m0, m3 ; byte -> word
|
||||
punpcklbw m1, m3 ; byte -> word
|
||||
punpcklbw m4, m3 ; byte -> word
|
||||
punpcklbw m5, m3 ; byte -> word
|
||||
%endif ; %1 == 8
|
||||
|
||||
; multiply
|
||||
%if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
|
||||
; add back 0x8000 * sum(coeffs) after the horizontal add
|
||||
psubw m0, m6
|
||||
psubw m1, m6
|
||||
psubw m4, m6
|
||||
psubw m5, m6
|
||||
%endif ; %1 == 16
|
||||
pmaddwd m0, [filterq+wq*8+mmsize*0] ; *= filter[{0,1,..,6,7}]
|
||||
pmaddwd m1, [filterq+wq*8+mmsize*1] ; *= filter[{8,9,..,14,15}]
|
||||
pmaddwd m4, [filterq+wq*8+mmsize*2] ; *= filter[{16,17,..,22,23}]
|
||||
pmaddwd m5, [filterq+wq*8+mmsize*3] ; *= filter[{24,25,..,30,31}]
|
||||
|
||||
; add up horizontally (8 srcpix * 8 coefficients -> 1 dstpix)
|
||||
%if notcpuflag(ssse3) ; sse2
|
||||
%if %1 == 8
|
||||
%define mex m6
|
||||
%else
|
||||
%define mex m3
|
||||
%endif
|
||||
; emulate horizontal add as transpose + vertical add
|
||||
mova mex, m0
|
||||
punpckldq m0, m1
|
||||
punpckhdq mex, m1
|
||||
paddd m0, mex
|
||||
mova m1, m4
|
||||
punpckldq m4, m5
|
||||
punpckhdq m1, m5
|
||||
paddd m4, m1
|
||||
mova m1, m0
|
||||
punpcklqdq m0, m4
|
||||
punpckhqdq m1, m4
|
||||
paddd m0, m1
|
||||
%else ; ssse3/sse4
|
||||
; FIXME if we rearrange the filter in pairs of 4, we can
|
||||
; load pixels likewise and use 2 x paddd + phaddd instead
|
||||
; of 3 x phaddd here, faster on older cpus
|
||||
phaddd m0, m1
|
||||
phaddd m4, m5
|
||||
phaddd m0, m4 ; filter[{ 0, 1,..., 6, 7}]*src[filterPos[0]+{0,1,...,6,7}],
|
||||
; filter[{ 8, 9,...,14,15}]*src[filterPos[1]+{0,1,...,6,7}],
|
||||
; filter[{16,17,...,22,23}]*src[filterPos[2]+{0,1,...,6,7}],
|
||||
; filter[{24,25,...,30,31}]*src[filterPos[3]+{0,1,...,6,7}]
|
||||
%endif ; sse2/ssse3/sse4
|
||||
%endif ; %3 == 4/8
|
||||
|
||||
%else ; %3 == X, i.e. any filterSize scaling
|
||||
|
||||
%ifidn %4, X4
|
||||
%define dlt 4
|
||||
%else ; %4 == X || %4 == X8
|
||||
%define dlt 0
|
||||
%endif ; %4 ==/!= X4
|
||||
%if ARCH_X86_64
|
||||
%define srcq r8
|
||||
%define pos1q r7
|
||||
%define srcendq r9
|
||||
movsxd fltsizeq, fltsized ; filterSize
|
||||
lea srcendq, [srcmemq+(fltsizeq-dlt)*srcmul] ; &src[filterSize&~4]
|
||||
%else ; x86-32
|
||||
%define srcq srcmemq
|
||||
%define pos1q dstq
|
||||
%define srcendq r6m
|
||||
lea pos0q, [srcmemq+(fltsizeq-dlt)*srcmul] ; &src[filterSize&~4]
|
||||
mov srcendq, pos0q
|
||||
%endif ; x86-32/64
|
||||
lea fltposq, [fltposq+wq*4]
|
||||
%if %2 == 15
|
||||
lea dstq, [dstq+wq*2]
|
||||
%else ; %2 == 19
|
||||
lea dstq, [dstq+wq*4]
|
||||
%endif ; %2 == 15/19
|
||||
movifnidn dstmp, dstq
|
||||
neg wq
|
||||
|
||||
.loop:
|
||||
mov32 pos0q, dword [fltposq+wq*4+0] ; filterPos[0]
|
||||
mov32 pos1q, dword [fltposq+wq*4+4] ; filterPos[1]
|
||||
; FIXME maybe do 4px/iteration on x86-64 (x86-32 wouldn't have enough regs)?
|
||||
pxor m4, m4
|
||||
pxor m5, m5
|
||||
mov srcq, srcmemmp
|
||||
|
||||
.innerloop:
|
||||
; load 2x8 (sse) source pixels into m0/m1 -> m4/m5
|
||||
movbh m0, [srcq+ pos0q *srcmul] ; src[filterPos[0] + {0,1,2,3(,4,5,6,7)}]
|
||||
movbh m1, [srcq+(pos1q+dlt)*srcmul] ; src[filterPos[1] + {0,1,2,3(,4,5,6,7)}]
|
||||
%if %1 == 8
|
||||
punpcklbw m0, m3
|
||||
punpcklbw m1, m3
|
||||
%endif ; %1 == 8
|
||||
|
||||
; multiply
|
||||
%if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
|
||||
; add back 0x8000 * sum(coeffs) after the horizontal add
|
||||
psubw m0, m6
|
||||
psubw m1, m6
|
||||
%endif ; %1 == 16
|
||||
pmaddwd m0, [filterq] ; filter[{0,1,2,3(,4,5,6,7)}]
|
||||
pmaddwd m1, [filterq+(fltsizeq+dlt)*2]; filter[filtersize+{0,1,2,3(,4,5,6,7)}]
|
||||
paddd m4, m0
|
||||
paddd m5, m1
|
||||
add filterq, mmsize
|
||||
add srcq, srcmul*mmsize/2
|
||||
cmp srcq, srcendq ; while (src += 4) < &src[filterSize]
|
||||
jl .innerloop
|
||||
|
||||
%ifidn %4, X4
|
||||
mov32 pos1q, dword [fltposq+wq*4+4] ; filterPos[1]
|
||||
movlh m0, [srcq+ pos0q *srcmul] ; split last 4 srcpx of dstpx[0]
|
||||
sub pos1q, fltsizeq ; and first 4 srcpx of dstpx[1]
|
||||
%if %1 > 8
|
||||
movhps m0, [srcq+(pos1q+dlt)*srcmul]
|
||||
%else ; %1 == 8
|
||||
movd m1, [srcq+(pos1q+dlt)*srcmul]
|
||||
punpckldq m0, m1
|
||||
%endif ; %1 == 8
|
||||
%if %1 == 8
|
||||
punpcklbw m0, m3
|
||||
%endif ; %1 == 8
|
||||
%if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
|
||||
; add back 0x8000 * sum(coeffs) after the horizontal add
|
||||
psubw m0, m6
|
||||
%endif ; %1 == 16
|
||||
pmaddwd m0, [filterq]
|
||||
%endif ; %4 == X4
|
||||
|
||||
lea filterq, [filterq+(fltsizeq+dlt)*2]
|
||||
|
||||
%if notcpuflag(ssse3) ; sse2
|
||||
mova m1, m4
|
||||
punpcklqdq m4, m5
|
||||
punpckhqdq m1, m5
|
||||
paddd m4, m1
|
||||
%else ; ssse3/sse4
|
||||
phaddd m4, m5
|
||||
%endif ; sse2/ssse3/sse4
|
||||
%ifidn %4, X4
|
||||
paddd m4, m0
|
||||
%endif ; %3 == X4
|
||||
%if notcpuflag(ssse3) ; sse2
|
||||
pshufd m4, m4, 11011000b
|
||||
movhlps m0, m4
|
||||
paddd m0, m4
|
||||
%else ; ssse3/sse4
|
||||
phaddd m4, m4
|
||||
SWAP 0, 4
|
||||
%endif ; sse2/ssse3/sse4
|
||||
%endif ; %3 ==/!= X
|
||||
|
||||
%if %1 == 16 ; add 0x8000 * sum(coeffs), i.e. back from signed -> unsigned
|
||||
paddd m0, m7
|
||||
%endif ; %1 == 16
|
||||
|
||||
; clip, store
|
||||
psrad m0, 14 + %1 - %2
|
||||
%ifidn %3, X
|
||||
movifnidn dstq, dstmp
|
||||
%endif ; %3 == X
|
||||
%if %2 == 15
|
||||
packssdw m0, m0
|
||||
%ifnidn %3, X
|
||||
movh [dstq+wq*(2>>wshr)], m0
|
||||
%else ; %3 == X
|
||||
movd [dstq+wq*2], m0
|
||||
%endif ; %3 ==/!= X
|
||||
%else ; %2 == 19
|
||||
PMINSD m0, m2, m4
|
||||
%ifnidn %3, X
|
||||
mova [dstq+wq*(4>>wshr)], m0
|
||||
%else ; %3 == X
|
||||
movq [dstq+wq*4], m0
|
||||
%endif ; %3 ==/!= X
|
||||
%endif ; %2 == 15/19
|
||||
%ifnidn %3, X
|
||||
add wq, (mmsize<<wshr)/4 ; both 8tap and 4tap really only do 4 pixels
|
||||
; per iteration. see "shl wq,1" above as for why we do this
|
||||
%else ; %3 == X
|
||||
add wq, 2
|
||||
%endif ; %3 ==/!= X
|
||||
jl .loop
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
; SCALE_FUNCS source_width, intermediate_nbits, n_xmm
|
||||
%macro SCALE_FUNCS 3
|
||||
SCALE_FUNC %1, %2, 4, 4, 6, %3
|
||||
SCALE_FUNC %1, %2, 8, 8, 6, %3
|
||||
SCALE_FUNC %1, %2, X, X4, 7, %3
|
||||
SCALE_FUNC %1, %2, X, X8, 7, %3
|
||||
%endmacro
|
||||
|
||||
; SCALE_FUNCS2 8_xmm_args, 9to10_xmm_args, 16_xmm_args
|
||||
%macro SCALE_FUNCS2 3
|
||||
%if notcpuflag(sse4)
|
||||
SCALE_FUNCS 8, 15, %1
|
||||
SCALE_FUNCS 9, 15, %2
|
||||
SCALE_FUNCS 10, 15, %2
|
||||
SCALE_FUNCS 12, 15, %2
|
||||
SCALE_FUNCS 14, 15, %2
|
||||
SCALE_FUNCS 16, 15, %3
|
||||
%endif ; !sse4
|
||||
SCALE_FUNCS 8, 19, %1
|
||||
SCALE_FUNCS 9, 19, %2
|
||||
SCALE_FUNCS 10, 19, %2
|
||||
SCALE_FUNCS 12, 19, %2
|
||||
SCALE_FUNCS 14, 19, %2
|
||||
SCALE_FUNCS 16, 19, %3
|
||||
%endmacro
|
||||
|
||||
INIT_XMM sse2
|
||||
SCALE_FUNCS2 7, 6, 8
|
||||
INIT_XMM ssse3
|
||||
SCALE_FUNCS2 6, 6, 8
|
||||
INIT_XMM sse4
|
||||
SCALE_FUNCS2 6, 6, 8
|
||||
@@ -0,0 +1,156 @@
|
||||
;******************************************************************************
|
||||
;* x86-optimized horizontal line scaling functions
|
||||
;* Copyright 2020 Google LLC
|
||||
;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@gmail.com>
|
||||
;*
|
||||
;* 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_RODATA 32
|
||||
|
||||
swizzle: dd 0, 4, 1, 5, 2, 6, 3, 7
|
||||
four: times 8 dd 4
|
||||
|
||||
SECTION .text
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; horizontal line scaling
|
||||
;
|
||||
; void hscale8to15_<filterSize>_<opt>
|
||||
; (SwsInternal *c, int16_t *dst,
|
||||
; int dstW, const uint8_t *src,
|
||||
; const int16_t *filter,
|
||||
; const int32_t *filterPos, int filterSize);
|
||||
;
|
||||
; Scale one horizontal line. Input is 8-bit width Filter is 14 bits. Output is
|
||||
; 15 bits (in int16_t). Each output pixel is generated from $filterSize input
|
||||
; pixels, the position of the first pixel is given in filterPos[nOutputPixel].
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
%macro SCALE_FUNC 1
|
||||
cglobal hscale8to15_%1, 7, 9, 16, pos0, dst, w, srcmem, filter, fltpos, fltsize, count, inner
|
||||
pxor m0, m0
|
||||
mova m15, [swizzle]
|
||||
xor countq, countq
|
||||
movsxd wq, wd
|
||||
%ifidn %1, X4
|
||||
mova m14, [four]
|
||||
shr fltsized, 2
|
||||
%endif
|
||||
cmp wq, 0x10
|
||||
jl .tail_loop
|
||||
sub wq, 0x10
|
||||
.loop:
|
||||
movu m1, [fltposq]
|
||||
movu m2, [fltposq+32]
|
||||
%ifidn %1, X4
|
||||
pxor m9, m9
|
||||
pxor m10, m10
|
||||
pxor m11, m11
|
||||
pxor m12, m12
|
||||
xor innerq, innerq
|
||||
.innerloop:
|
||||
%endif
|
||||
vpcmpeqd m13, m13
|
||||
vpgatherdd m3,[srcmemq + m1], m13
|
||||
vpcmpeqd m13, m13
|
||||
vpgatherdd m4,[srcmemq + m2], m13
|
||||
vpunpcklbw m5, m3, m0
|
||||
vpunpckhbw m6, m3, m0
|
||||
vpunpcklbw m7, m4, m0
|
||||
vpunpckhbw m8, m4, m0
|
||||
vpmaddwd m5, m5, [filterq]
|
||||
vpmaddwd m6, m6, [filterq + 32]
|
||||
vpmaddwd m7, m7, [filterq + 64]
|
||||
vpmaddwd m8, m8, [filterq + 96]
|
||||
add filterq, 0x80
|
||||
%ifidn %1, X4
|
||||
paddd m9, m5
|
||||
paddd m10, m6
|
||||
paddd m11, m7
|
||||
paddd m12, m8
|
||||
paddd m1, m14
|
||||
paddd m2, m14
|
||||
add innerq, 1
|
||||
cmp innerq, fltsizeq
|
||||
jl .innerloop
|
||||
vphaddd m5, m9, m10
|
||||
vphaddd m6, m11, m12
|
||||
%else
|
||||
vphaddd m5, m5, m6
|
||||
vphaddd m6, m7, m8
|
||||
%endif
|
||||
vpsrad m5, 7
|
||||
vpsrad m6, 7
|
||||
vpackssdw m5, m5, m6
|
||||
vpermd m5, m15, m5
|
||||
vmovdqu [dstq + countq * 2], m5
|
||||
add fltposq, 0x40
|
||||
add countq, 0x10
|
||||
cmp countq, wq
|
||||
jle .loop
|
||||
|
||||
add wq, 0x10
|
||||
cmp countq, wq
|
||||
jge .end
|
||||
|
||||
.tail_loop:
|
||||
movu xm1, [fltposq]
|
||||
%ifidn %1, X4
|
||||
pxor xm9, xm9
|
||||
pxor xm10, xm10
|
||||
xor innerq, innerq
|
||||
.tail_innerloop:
|
||||
%endif
|
||||
vpcmpeqd xm13, xm13
|
||||
vpgatherdd xm3,[srcmemq + xm1], xm13
|
||||
vpunpcklbw xm5, xm3, xm0
|
||||
vpunpckhbw xm6, xm3, xm0
|
||||
vpmaddwd xm5, xm5, [filterq]
|
||||
vpmaddwd xm6, xm6, [filterq + 0x10]
|
||||
add filterq, 0x20
|
||||
%ifidn %1, X4
|
||||
paddd xm9, xm5
|
||||
paddd xm10, xm6
|
||||
paddd xm1, xm14
|
||||
add innerq, 1
|
||||
cmp innerq, fltsizeq
|
||||
jl .tail_innerloop
|
||||
vphaddd xm5, xm9, xm10
|
||||
%else
|
||||
vphaddd xm5, xm5, xm6
|
||||
%endif
|
||||
vpsrad xm5, 7
|
||||
vpackssdw xm5, xm5, xm5
|
||||
vmovq [dstq + countq * 2], xm5
|
||||
add fltposq, 0x10
|
||||
add countq, 0x4
|
||||
cmp countq, wq
|
||||
jl .tail_loop
|
||||
.end:
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
%if ARCH_X86_64
|
||||
%if HAVE_AVX2_EXTERNAL
|
||||
INIT_YMM avx2
|
||||
SCALE_FUNC 4
|
||||
SCALE_FUNC X4
|
||||
%endif
|
||||
%endif
|
||||
@@ -0,0 +1,854 @@
|
||||
/*
|
||||
* 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 <inttypes.h>
|
||||
#include "config.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/x86/cpu.h"
|
||||
#include "libavutil/cpu.h"
|
||||
#include "libavutil/mem_internal.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
|
||||
const DECLARE_ALIGNED(8, uint64_t, ff_dither4)[2] = {
|
||||
0x0103010301030103LL,
|
||||
0x0200020002000200LL,};
|
||||
|
||||
const DECLARE_ALIGNED(8, uint64_t, ff_dither8)[2] = {
|
||||
0x0602060206020602LL,
|
||||
0x0004000400040004LL,};
|
||||
|
||||
#if HAVE_INLINE_ASM
|
||||
|
||||
DECLARE_ASM_CONST(8, uint64_t, bF8)= 0xF8F8F8F8F8F8F8F8LL;
|
||||
DECLARE_ASM_CONST(8, uint64_t, bFC)= 0xFCFCFCFCFCFCFCFCLL;
|
||||
|
||||
DECLARE_ASM_CONST(8, uint64_t, M24A) = 0x00FF0000FF0000FFLL;
|
||||
DECLARE_ASM_CONST(8, uint64_t, M24B) = 0xFF0000FF0000FF00LL;
|
||||
DECLARE_ASM_CONST(8, uint64_t, M24C) = 0x0000FF0000FF0000LL;
|
||||
|
||||
// MMXEXT versions
|
||||
#if HAVE_MMXEXT_INLINE
|
||||
#undef RENAME
|
||||
#undef COMPILE_TEMPLATE_MMXEXT
|
||||
#define COMPILE_TEMPLATE_MMXEXT 1
|
||||
#define RENAME(a) a ## _mmxext
|
||||
#include "swscale_template.c"
|
||||
#endif
|
||||
|
||||
void ff_updateMMXDitherTables(SwsInternal *c, int dstY)
|
||||
{
|
||||
const int dstH= c->opts.dst_h;
|
||||
const int flags= c->opts.flags;
|
||||
|
||||
SwsPlane *lumPlane = &c->slice[c->numSlice-2].plane[0];
|
||||
SwsPlane *chrUPlane = &c->slice[c->numSlice-2].plane[1];
|
||||
SwsPlane *alpPlane = &c->slice[c->numSlice-2].plane[3];
|
||||
|
||||
int hasAlpha = c->needAlpha;
|
||||
int32_t *vLumFilterPos= c->vLumFilterPos;
|
||||
int32_t *vChrFilterPos= c->vChrFilterPos;
|
||||
int16_t *vLumFilter= c->vLumFilter;
|
||||
int16_t *vChrFilter= c->vChrFilter;
|
||||
int32_t *lumMmxFilter= c->lumMmxFilter;
|
||||
int32_t *chrMmxFilter= c->chrMmxFilter;
|
||||
int32_t av_unused *alpMmxFilter= c->alpMmxFilter;
|
||||
const int vLumFilterSize= c->vLumFilterSize;
|
||||
const int vChrFilterSize= c->vChrFilterSize;
|
||||
const int chrDstY= dstY>>c->chrDstVSubSample;
|
||||
const int firstLumSrcY= vLumFilterPos[dstY]; //First line needed as input
|
||||
const int firstChrSrcY= vChrFilterPos[chrDstY]; //First line needed as input
|
||||
|
||||
c->blueDither= ff_dither8[dstY&1];
|
||||
if (c->opts.dst_format == AV_PIX_FMT_RGB555 || c->opts.dst_format == AV_PIX_FMT_BGR555)
|
||||
c->greenDither= ff_dither8[dstY&1];
|
||||
else
|
||||
c->greenDither= ff_dither4[dstY&1];
|
||||
c->redDither= ff_dither8[(dstY+1)&1];
|
||||
if (dstY < dstH - 2) {
|
||||
const int16_t **lumSrcPtr = (const int16_t **)(void*) lumPlane->line + firstLumSrcY - lumPlane->sliceY;
|
||||
const int16_t **chrUSrcPtr = (const int16_t **)(void*) chrUPlane->line + firstChrSrcY - chrUPlane->sliceY;
|
||||
const int16_t **alpSrcPtr = (CONFIG_SWSCALE_ALPHA && hasAlpha) ? (const int16_t **)(void*) alpPlane->line + firstLumSrcY - alpPlane->sliceY : NULL;
|
||||
|
||||
int i;
|
||||
if (firstLumSrcY < 0 || firstLumSrcY + vLumFilterSize > c->opts.src_h) {
|
||||
const int16_t **tmpY = (const int16_t **) lumPlane->tmp;
|
||||
|
||||
int neg = -firstLumSrcY, i, end = FFMIN(c->opts.src_h - firstLumSrcY, vLumFilterSize);
|
||||
for (i = 0; i < neg; i++)
|
||||
tmpY[i] = lumSrcPtr[neg];
|
||||
for ( ; i < end; i++)
|
||||
tmpY[i] = lumSrcPtr[i];
|
||||
for ( ; i < vLumFilterSize; i++)
|
||||
tmpY[i] = tmpY[i-1];
|
||||
lumSrcPtr = tmpY;
|
||||
|
||||
if (alpSrcPtr) {
|
||||
const int16_t **tmpA = (const int16_t **) alpPlane->tmp;
|
||||
for (i = 0; i < neg; i++)
|
||||
tmpA[i] = alpSrcPtr[neg];
|
||||
for ( ; i < end; i++)
|
||||
tmpA[i] = alpSrcPtr[i];
|
||||
for ( ; i < vLumFilterSize; i++)
|
||||
tmpA[i] = tmpA[i - 1];
|
||||
alpSrcPtr = tmpA;
|
||||
}
|
||||
}
|
||||
if (firstChrSrcY < 0 || firstChrSrcY + vChrFilterSize > c->chrSrcH) {
|
||||
const int16_t **tmpU = (const int16_t **) chrUPlane->tmp;
|
||||
int neg = -firstChrSrcY, i, end = FFMIN(c->chrSrcH - firstChrSrcY, vChrFilterSize);
|
||||
for (i = 0; i < neg; i++) {
|
||||
tmpU[i] = chrUSrcPtr[neg];
|
||||
}
|
||||
for ( ; i < end; i++) {
|
||||
tmpU[i] = chrUSrcPtr[i];
|
||||
}
|
||||
for ( ; i < vChrFilterSize; i++) {
|
||||
tmpU[i] = tmpU[i - 1];
|
||||
}
|
||||
chrUSrcPtr = tmpU;
|
||||
}
|
||||
|
||||
if (flags & SWS_ACCURATE_RND) {
|
||||
int s= APCK_SIZE / 8;
|
||||
for (i=0; i<vLumFilterSize; i+=2) {
|
||||
*(const void**)&lumMmxFilter[s*i ]= lumSrcPtr[i ];
|
||||
*(const void**)&lumMmxFilter[s*i+APCK_PTR2/4 ]= lumSrcPtr[i+(vLumFilterSize>1)];
|
||||
lumMmxFilter[s*i+APCK_COEF/4 ]=
|
||||
lumMmxFilter[s*i+APCK_COEF/4+1]= vLumFilter[dstY*vLumFilterSize + i ]
|
||||
+ (vLumFilterSize>1 ? vLumFilter[dstY*vLumFilterSize + i + 1] * (1 << 16) : 0);
|
||||
if (CONFIG_SWSCALE_ALPHA && hasAlpha) {
|
||||
*(const void**)&alpMmxFilter[s*i ]= alpSrcPtr[i ];
|
||||
*(const void**)&alpMmxFilter[s*i+APCK_PTR2/4 ]= alpSrcPtr[i+(vLumFilterSize>1)];
|
||||
alpMmxFilter[s*i+APCK_COEF/4 ]=
|
||||
alpMmxFilter[s*i+APCK_COEF/4+1]= lumMmxFilter[s*i+APCK_COEF/4 ];
|
||||
}
|
||||
}
|
||||
for (i=0; i<vChrFilterSize; i+=2) {
|
||||
*(const void**)&chrMmxFilter[s*i ]= chrUSrcPtr[i ];
|
||||
*(const void**)&chrMmxFilter[s*i+APCK_PTR2/4 ]= chrUSrcPtr[i+(vChrFilterSize>1)];
|
||||
chrMmxFilter[s*i+APCK_COEF/4 ]=
|
||||
chrMmxFilter[s*i+APCK_COEF/4+1]= vChrFilter[chrDstY*vChrFilterSize + i ]
|
||||
+ (vChrFilterSize>1 ? vChrFilter[chrDstY*vChrFilterSize + i + 1] * (1 << 16) : 0);
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<vLumFilterSize; i++) {
|
||||
*(const void**)&lumMmxFilter[4*i+0]= lumSrcPtr[i];
|
||||
lumMmxFilter[4*i+2]=
|
||||
lumMmxFilter[4*i+3]=
|
||||
((uint16_t)vLumFilter[dstY*vLumFilterSize + i])*0x10001U;
|
||||
if (CONFIG_SWSCALE_ALPHA && hasAlpha) {
|
||||
*(const void**)&alpMmxFilter[4*i+0]= alpSrcPtr[i];
|
||||
alpMmxFilter[4*i+2]=
|
||||
alpMmxFilter[4*i+3]= lumMmxFilter[4*i+2];
|
||||
}
|
||||
}
|
||||
for (i=0; i<vChrFilterSize; i++) {
|
||||
*(const void**)&chrMmxFilter[4*i+0]= chrUSrcPtr[i];
|
||||
chrMmxFilter[4*i+2]=
|
||||
chrMmxFilter[4*i+3]=
|
||||
((uint16_t)vChrFilter[chrDstY*vChrFilterSize + i])*0x10001U;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_INLINE_ASM */
|
||||
|
||||
#define YUV2YUVX_FUNC_MMX(opt, step) \
|
||||
void ff_yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, int srcOffset, \
|
||||
uint8_t *dest, int dstW, \
|
||||
const uint8_t *dither, int offset); \
|
||||
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) \
|
||||
{ \
|
||||
if(dstW > 0) \
|
||||
ff_yuv2yuvX_ ##opt(filter, filterSize - 1, 0, dest - offset, dstW + offset, dither, offset); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define YUV2YUVX_FUNC(opt, step) \
|
||||
void ff_yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, int srcOffset, \
|
||||
uint8_t *dest, int dstW, \
|
||||
const uint8_t *dither, int offset); \
|
||||
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) \
|
||||
{ \
|
||||
int remainder = (dstW % step); \
|
||||
int pixelsProcessed = dstW - remainder; \
|
||||
if(((uintptr_t)dest) & 15){ \
|
||||
yuv2yuvX_mmxext(filter, filterSize, src, dest, dstW, dither, offset); \
|
||||
return; \
|
||||
} \
|
||||
if(pixelsProcessed > 0) \
|
||||
ff_yuv2yuvX_ ##opt(filter, filterSize - 1, 0, dest - offset, pixelsProcessed + offset, dither, offset); \
|
||||
if(remainder > 0){ \
|
||||
ff_yuv2yuvX_mmxext(filter, filterSize - 1, pixelsProcessed, dest - offset, pixelsProcessed + remainder + offset, dither, offset); \
|
||||
} \
|
||||
return; \
|
||||
}
|
||||
|
||||
#if HAVE_MMXEXT_EXTERNAL
|
||||
YUV2YUVX_FUNC_MMX(mmxext, 16)
|
||||
#endif
|
||||
#if HAVE_SSE3_EXTERNAL
|
||||
YUV2YUVX_FUNC(sse3, 32)
|
||||
#endif
|
||||
#if HAVE_AVX2_EXTERNAL
|
||||
YUV2YUVX_FUNC(avx2, 64)
|
||||
#endif
|
||||
|
||||
#define SCALE_FUNC(filter_n, from_bpc, to_bpc, opt) \
|
||||
void ff_hscale ## from_bpc ## to ## to_bpc ## _ ## filter_n ## _ ## opt( \
|
||||
SwsInternal *c, int16_t *data, \
|
||||
int dstW, const uint8_t *src, \
|
||||
const int16_t *filter, \
|
||||
const int32_t *filterPos, int filterSize)
|
||||
|
||||
#define SCALE_FUNCS(filter_n, opt) \
|
||||
SCALE_FUNC(filter_n, 8, 15, opt); \
|
||||
SCALE_FUNC(filter_n, 9, 15, opt); \
|
||||
SCALE_FUNC(filter_n, 10, 15, opt); \
|
||||
SCALE_FUNC(filter_n, 12, 15, opt); \
|
||||
SCALE_FUNC(filter_n, 14, 15, opt); \
|
||||
SCALE_FUNC(filter_n, 16, 15, opt); \
|
||||
SCALE_FUNC(filter_n, 8, 19, opt); \
|
||||
SCALE_FUNC(filter_n, 9, 19, opt); \
|
||||
SCALE_FUNC(filter_n, 10, 19, opt); \
|
||||
SCALE_FUNC(filter_n, 12, 19, opt); \
|
||||
SCALE_FUNC(filter_n, 14, 19, opt); \
|
||||
SCALE_FUNC(filter_n, 16, 19, opt)
|
||||
|
||||
#define SCALE_FUNCS_MMX(opt) \
|
||||
SCALE_FUNCS(4, opt); \
|
||||
SCALE_FUNCS(8, opt); \
|
||||
SCALE_FUNCS(X, opt)
|
||||
|
||||
#define SCALE_FUNCS_SSE(opt) \
|
||||
SCALE_FUNCS(4, opt); \
|
||||
SCALE_FUNCS(8, opt); \
|
||||
SCALE_FUNCS(X4, opt); \
|
||||
SCALE_FUNCS(X8, opt)
|
||||
|
||||
SCALE_FUNCS_SSE(sse2);
|
||||
SCALE_FUNCS_SSE(ssse3);
|
||||
SCALE_FUNCS_SSE(sse4);
|
||||
|
||||
SCALE_FUNC(4, 8, 15, avx2);
|
||||
SCALE_FUNC(X4, 8, 15, avx2);
|
||||
|
||||
#define VSCALEX_FUNC(size, opt) \
|
||||
void ff_yuv2planeX_ ## size ## _ ## opt(const int16_t *filter, int filterSize, \
|
||||
const int16_t **src, uint8_t *dest, int dstW, \
|
||||
const uint8_t *dither, int offset)
|
||||
#define VSCALEX_FUNCS(opt) \
|
||||
VSCALEX_FUNC(8, opt); \
|
||||
VSCALEX_FUNC(9, opt); \
|
||||
VSCALEX_FUNC(10, opt)
|
||||
|
||||
VSCALEX_FUNC(8, mmxext);
|
||||
VSCALEX_FUNCS(sse2);
|
||||
VSCALEX_FUNCS(sse4);
|
||||
VSCALEX_FUNC(16, sse4);
|
||||
VSCALEX_FUNCS(avx);
|
||||
|
||||
#define VSCALE_FUNC(size, opt) \
|
||||
void ff_yuv2plane1_ ## size ## _ ## opt(const int16_t *src, uint8_t *dst, int dstW, \
|
||||
const uint8_t *dither, int offset)
|
||||
#define VSCALE_FUNCS(opt1, opt2) \
|
||||
VSCALE_FUNC(8, opt1); \
|
||||
VSCALE_FUNC(9, opt2); \
|
||||
VSCALE_FUNC(10, opt2); \
|
||||
VSCALE_FUNC(16, opt1)
|
||||
|
||||
VSCALE_FUNCS(sse2, sse2);
|
||||
VSCALE_FUNC(16, sse4);
|
||||
VSCALE_FUNCS(avx, avx);
|
||||
|
||||
#define INPUT_Y_FUNC(fmt, opt) \
|
||||
void ff_ ## fmt ## ToY_ ## opt(uint8_t *dst, const uint8_t *src, \
|
||||
const uint8_t *unused1, const uint8_t *unused2, \
|
||||
int w, uint32_t *unused, void *opq)
|
||||
#define INPUT_UV_FUNC(fmt, opt) \
|
||||
void ff_ ## fmt ## ToUV_ ## opt(uint8_t *dstU, uint8_t *dstV, \
|
||||
const uint8_t *unused0, \
|
||||
const uint8_t *src1, \
|
||||
const uint8_t *src2, \
|
||||
int w, uint32_t *unused, void *opq)
|
||||
#define INPUT_FUNC(fmt, opt) \
|
||||
INPUT_Y_FUNC(fmt, opt); \
|
||||
INPUT_UV_FUNC(fmt, opt)
|
||||
#define INPUT_FUNCS(opt) \
|
||||
INPUT_FUNC(uyvy, opt); \
|
||||
INPUT_FUNC(yuyv, opt); \
|
||||
INPUT_UV_FUNC(nv12, opt); \
|
||||
INPUT_UV_FUNC(nv21, opt); \
|
||||
INPUT_FUNC(rgba, opt); \
|
||||
INPUT_FUNC(bgra, opt); \
|
||||
INPUT_FUNC(argb, opt); \
|
||||
INPUT_FUNC(abgr, opt); \
|
||||
INPUT_FUNC(rgb24, opt); \
|
||||
INPUT_FUNC(bgr24, opt)
|
||||
|
||||
INPUT_FUNCS(sse2);
|
||||
INPUT_FUNCS(ssse3);
|
||||
INPUT_FUNCS(avx);
|
||||
INPUT_FUNC(rgba, avx2);
|
||||
INPUT_FUNC(bgra, avx2);
|
||||
INPUT_FUNC(argb, avx2);
|
||||
INPUT_FUNC(abgr, avx2);
|
||||
INPUT_FUNC(rgb24, avx2);
|
||||
INPUT_FUNC(bgr24, avx2);
|
||||
|
||||
#if ARCH_X86_64
|
||||
#define YUV2NV_DECL(fmt, opt) \
|
||||
void ff_yuv2 ## fmt ## cX_ ## opt(enum AVPixelFormat format, const uint8_t *dither, \
|
||||
const int16_t *filter, int filterSize, \
|
||||
const int16_t **u, const int16_t **v, \
|
||||
uint8_t *dst, int dstWidth)
|
||||
|
||||
YUV2NV_DECL(nv12, avx2);
|
||||
YUV2NV_DECL(nv21, avx2);
|
||||
|
||||
#define YUV2GBRP_FN_DECL(fmt, opt) \
|
||||
void ff_yuv2##fmt##_full_X_ ##opt(SwsInternal *c, const int16_t *lumFilter, \
|
||||
const int16_t **lumSrcx, int lumFilterSize, \
|
||||
const int16_t *chrFilter, const int16_t **chrUSrcx, \
|
||||
const int16_t **chrVSrcx, int chrFilterSize, \
|
||||
const int16_t **alpSrcx, uint8_t **dest, \
|
||||
int dstW, int y)
|
||||
|
||||
#define YUV2GBRP_DECL(opt) \
|
||||
YUV2GBRP_FN_DECL(gbrp, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrap, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp9le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp10le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrap10le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp12le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrap12le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp14le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp16le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrap16le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrpf32le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrapf32le, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp9be, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp10be, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrap10be, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp12be, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrap12be, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp14be, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrp16be, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrap16be, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrpf32be, opt); \
|
||||
YUV2GBRP_FN_DECL(gbrapf32be, opt)
|
||||
|
||||
YUV2GBRP_DECL(sse2);
|
||||
YUV2GBRP_DECL(sse4);
|
||||
YUV2GBRP_DECL(avx2);
|
||||
|
||||
#define INPUT_PLANAR_RGB_Y_FN_DECL(fmt, opt) \
|
||||
void ff_planar_##fmt##_to_y_##opt(uint8_t *dst, \
|
||||
const uint8_t *src[4], int w, int32_t *rgb2yuv, \
|
||||
void *opq)
|
||||
|
||||
#define INPUT_PLANAR_RGB_UV_FN_DECL(fmt, opt) \
|
||||
void ff_planar_##fmt##_to_uv_##opt(uint8_t *dstU, uint8_t *dstV, \
|
||||
const uint8_t *src[4], int w, int32_t *rgb2yuv, \
|
||||
void *opq)
|
||||
|
||||
#define INPUT_PLANAR_RGB_A_FN_DECL(fmt, opt) \
|
||||
void ff_planar_##fmt##_to_a_##opt(uint8_t *dst, \
|
||||
const uint8_t *src[4], int w, int32_t *rgb2yuv, \
|
||||
void *opq)
|
||||
|
||||
|
||||
#define INPUT_PLANAR_RGBXX_A_DECL(fmt, opt) \
|
||||
INPUT_PLANAR_RGB_A_FN_DECL(fmt##le, opt); \
|
||||
INPUT_PLANAR_RGB_A_FN_DECL(fmt##be, opt)
|
||||
|
||||
#define INPUT_PLANAR_RGBXX_Y_DECL(fmt, opt) \
|
||||
INPUT_PLANAR_RGB_Y_FN_DECL(fmt##le, opt); \
|
||||
INPUT_PLANAR_RGB_Y_FN_DECL(fmt##be, opt)
|
||||
|
||||
#define INPUT_PLANAR_RGBXX_UV_DECL(fmt, opt) \
|
||||
INPUT_PLANAR_RGB_UV_FN_DECL(fmt##le, opt); \
|
||||
INPUT_PLANAR_RGB_UV_FN_DECL(fmt##be, opt)
|
||||
|
||||
#define INPUT_PLANAR_RGBXX_YUVA_DECL(fmt, opt) \
|
||||
INPUT_PLANAR_RGBXX_Y_DECL(fmt, opt); \
|
||||
INPUT_PLANAR_RGBXX_UV_DECL(fmt, opt); \
|
||||
INPUT_PLANAR_RGBXX_A_DECL(fmt, opt)
|
||||
|
||||
#define INPUT_PLANAR_RGBXX_YUV_DECL(fmt, opt) \
|
||||
INPUT_PLANAR_RGBXX_Y_DECL(fmt, opt); \
|
||||
INPUT_PLANAR_RGBXX_UV_DECL(fmt, opt)
|
||||
|
||||
#define INPUT_PLANAR_RGBXX_UVA_DECL(fmt, opt) \
|
||||
INPUT_PLANAR_RGBXX_UV_DECL(fmt, opt); \
|
||||
INPUT_PLANAR_RGBXX_A_DECL(fmt, opt)
|
||||
|
||||
#define INPUT_PLANAR_RGB_A_ALL_DECL(opt) \
|
||||
INPUT_PLANAR_RGB_A_FN_DECL(rgb, opt); \
|
||||
INPUT_PLANAR_RGBXX_A_DECL(rgb10, opt); \
|
||||
INPUT_PLANAR_RGBXX_A_DECL(rgb12, opt); \
|
||||
INPUT_PLANAR_RGBXX_A_DECL(rgb16, opt); \
|
||||
INPUT_PLANAR_RGBXX_A_DECL(rgbf32, opt)
|
||||
|
||||
#define INPUT_PLANAR_RGB_Y_ALL_DECL(opt) \
|
||||
INPUT_PLANAR_RGB_Y_FN_DECL(rgb, opt); \
|
||||
INPUT_PLANAR_RGBXX_Y_DECL(rgb9, opt); \
|
||||
INPUT_PLANAR_RGBXX_Y_DECL(rgb10, opt); \
|
||||
INPUT_PLANAR_RGBXX_Y_DECL(rgb12, opt); \
|
||||
INPUT_PLANAR_RGBXX_Y_DECL(rgb14, opt); \
|
||||
INPUT_PLANAR_RGBXX_Y_DECL(rgb16, opt); \
|
||||
INPUT_PLANAR_RGBXX_Y_DECL(rgbf32, opt)
|
||||
|
||||
#define INPUT_PLANAR_RGB_UV_ALL_DECL(opt) \
|
||||
INPUT_PLANAR_RGB_UV_FN_DECL(rgb, opt); \
|
||||
INPUT_PLANAR_RGBXX_UV_DECL(rgb9, opt); \
|
||||
INPUT_PLANAR_RGBXX_UV_DECL(rgb10, opt); \
|
||||
INPUT_PLANAR_RGBXX_UV_DECL(rgb12, opt); \
|
||||
INPUT_PLANAR_RGBXX_UV_DECL(rgb14, opt); \
|
||||
INPUT_PLANAR_RGBXX_UV_DECL(rgb16, opt); \
|
||||
INPUT_PLANAR_RGBXX_UV_DECL(rgbf32, opt)
|
||||
|
||||
INPUT_PLANAR_RGBXX_Y_DECL(rgbf32, sse2);
|
||||
INPUT_PLANAR_RGB_UV_ALL_DECL(sse2);
|
||||
INPUT_PLANAR_RGB_A_ALL_DECL(sse2);
|
||||
|
||||
INPUT_PLANAR_RGB_Y_ALL_DECL(sse4);
|
||||
INPUT_PLANAR_RGB_UV_ALL_DECL(sse4);
|
||||
INPUT_PLANAR_RGBXX_A_DECL(rgbf32, sse4);
|
||||
|
||||
INPUT_PLANAR_RGB_Y_ALL_DECL(avx2);
|
||||
INPUT_PLANAR_RGB_UV_ALL_DECL(avx2);
|
||||
INPUT_PLANAR_RGB_A_ALL_DECL(avx2);
|
||||
#endif
|
||||
|
||||
#define RANGE_CONVERT_FUNCS(opt, bpc) do { \
|
||||
if (c->opts.src_range) { \
|
||||
c->lumConvertRange = ff_lumRangeFromJpeg##bpc##_##opt; \
|
||||
c->chrConvertRange = ff_chrRangeFromJpeg##bpc##_##opt; \
|
||||
} else { \
|
||||
c->lumConvertRange = ff_lumRangeToJpeg##bpc##_##opt; \
|
||||
c->chrConvertRange = ff_chrRangeToJpeg##bpc##_##opt; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RANGE_CONVERT_FUNCS_DECL(opt, bpc) \
|
||||
void ff_lumRangeFromJpeg##bpc##_##opt(int16_t *dst, int width, \
|
||||
uint32_t coeff, int64_t offset); \
|
||||
void ff_chrRangeFromJpeg##bpc##_##opt(int16_t *dstU, int16_t *dstV, int width, \
|
||||
uint32_t coeff, int64_t offset); \
|
||||
void ff_lumRangeToJpeg##bpc##_##opt(int16_t *dst, int width, \
|
||||
uint32_t coeff, int64_t offset); \
|
||||
void ff_chrRangeToJpeg##bpc##_##opt(int16_t *dstU, int16_t *dstV, int width, \
|
||||
uint32_t coeff, int64_t offset); \
|
||||
|
||||
RANGE_CONVERT_FUNCS_DECL(sse2, 8)
|
||||
RANGE_CONVERT_FUNCS_DECL(sse4, 16)
|
||||
RANGE_CONVERT_FUNCS_DECL(avx2, 8)
|
||||
RANGE_CONVERT_FUNCS_DECL(avx2, 16)
|
||||
|
||||
av_cold void ff_sws_init_range_convert_x86(SwsInternal *c)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
if (EXTERNAL_AVX2_FAST(cpu_flags)) {
|
||||
if (c->dstBpc <= 14) {
|
||||
RANGE_CONVERT_FUNCS(avx2, 8);
|
||||
} else {
|
||||
RANGE_CONVERT_FUNCS(avx2, 16);
|
||||
}
|
||||
} else if (EXTERNAL_SSE2(cpu_flags) && c->dstBpc <= 14) {
|
||||
RANGE_CONVERT_FUNCS(sse2, 8);
|
||||
} else if (EXTERNAL_SSE4(cpu_flags) && c->dstBpc > 14) {
|
||||
RANGE_CONVERT_FUNCS(sse4, 16);
|
||||
}
|
||||
}
|
||||
|
||||
av_cold void ff_sws_init_swscale_x86(SwsInternal *c)
|
||||
{
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
#if HAVE_MMXEXT_INLINE
|
||||
if (INLINE_MMXEXT(cpu_flags))
|
||||
sws_init_swscale_mmxext(c);
|
||||
#endif
|
||||
if(c->use_mmx_vfilter && !(c->opts.flags & SWS_ACCURATE_RND)) {
|
||||
#if HAVE_MMXEXT_EXTERNAL
|
||||
if (EXTERNAL_MMXEXT(cpu_flags))
|
||||
c->yuv2planeX = yuv2yuvX_mmxext;
|
||||
#endif
|
||||
#if HAVE_SSE3_EXTERNAL
|
||||
if (EXTERNAL_SSE3(cpu_flags))
|
||||
c->yuv2planeX = yuv2yuvX_sse3;
|
||||
#endif
|
||||
#if HAVE_AVX2_EXTERNAL
|
||||
if (EXTERNAL_AVX2_FAST(cpu_flags))
|
||||
c->yuv2planeX = yuv2yuvX_avx2;
|
||||
#endif
|
||||
}
|
||||
#if ARCH_X86_32 && !HAVE_ALIGNED_STACK
|
||||
// The better yuv2planeX_8 functions need aligned stack on x86-32,
|
||||
// so we use MMXEXT in this case if they are not available.
|
||||
if (EXTERNAL_MMXEXT(cpu_flags)) {
|
||||
if (c->dstBpc == 8 && !c->use_mmx_vfilter)
|
||||
c->yuv2planeX = ff_yuv2planeX_8_mmxext;
|
||||
}
|
||||
#endif /* ARCH_X86_32 && !HAVE_ALIGNED_STACK */
|
||||
|
||||
#define ASSIGN_SCALE_FUNC2(hscalefn, filtersize, opt1, opt2) do { \
|
||||
if (c->srcBpc == 8) { \
|
||||
hscalefn = c->dstBpc <= 14 ? ff_hscale8to15_ ## filtersize ## _ ## opt2 : \
|
||||
ff_hscale8to19_ ## filtersize ## _ ## opt1; \
|
||||
} else if (c->srcBpc == 9) { \
|
||||
hscalefn = c->dstBpc <= 14 ? ff_hscale9to15_ ## filtersize ## _ ## opt2 : \
|
||||
ff_hscale9to19_ ## filtersize ## _ ## opt1; \
|
||||
} else if (c->srcBpc == 10) { \
|
||||
hscalefn = c->dstBpc <= 14 ? ff_hscale10to15_ ## filtersize ## _ ## opt2 : \
|
||||
ff_hscale10to19_ ## filtersize ## _ ## opt1; \
|
||||
} else if (c->srcBpc == 12) { \
|
||||
hscalefn = c->dstBpc <= 14 ? ff_hscale12to15_ ## filtersize ## _ ## opt2 : \
|
||||
ff_hscale12to19_ ## filtersize ## _ ## opt1; \
|
||||
} else if (c->srcBpc == 14 || ((c->opts.src_format==AV_PIX_FMT_PAL8||isAnyRGB(c->opts.src_format)) && av_pix_fmt_desc_get(c->opts.src_format)->comp[0].depth<16)) { \
|
||||
hscalefn = c->dstBpc <= 14 ? ff_hscale14to15_ ## filtersize ## _ ## opt2 : \
|
||||
ff_hscale14to19_ ## filtersize ## _ ## opt1; \
|
||||
} else { /* c->srcBpc == 16 */ \
|
||||
av_assert0(c->srcBpc == 16);\
|
||||
hscalefn = c->dstBpc <= 14 ? ff_hscale16to15_ ## filtersize ## _ ## opt2 : \
|
||||
ff_hscale16to19_ ## filtersize ## _ ## opt1; \
|
||||
} \
|
||||
} while (0)
|
||||
#define ASSIGN_VSCALEX_FUNC(vscalefn, opt, do_16_case, condition_8bit) \
|
||||
switch(c->dstBpc){ \
|
||||
case 16: do_16_case; break; \
|
||||
case 10: if (!isBE(c->opts.dst_format) && !isSemiPlanarYUV(c->opts.dst_format) && !isDataInHighBits(c->opts.dst_format)) vscalefn = ff_yuv2planeX_10_ ## opt; break; \
|
||||
case 9: if (!isBE(c->opts.dst_format)) vscalefn = ff_yuv2planeX_9_ ## opt; break; \
|
||||
case 8: if ((condition_8bit) && !c->use_mmx_vfilter) vscalefn = ff_yuv2planeX_8_ ## opt; break; \
|
||||
}
|
||||
#define ASSIGN_VSCALE_FUNC(vscalefn, opt) \
|
||||
switch(c->dstBpc){ \
|
||||
case 16: if (!isBE(c->opts.dst_format)) vscalefn = ff_yuv2plane1_16_ ## opt; break; \
|
||||
case 10: if (!isBE(c->opts.dst_format) && !isSemiPlanarYUV(c->opts.dst_format) && !isDataInHighBits(c->opts.dst_format)) vscalefn = ff_yuv2plane1_10_ ## opt; break; \
|
||||
case 9: if (!isBE(c->opts.dst_format)) vscalefn = ff_yuv2plane1_9_ ## opt; break; \
|
||||
case 8: vscalefn = ff_yuv2plane1_8_ ## opt; break; \
|
||||
default: av_assert0(c->dstBpc>8); \
|
||||
}
|
||||
#define case_rgb(x, X, opt) \
|
||||
case AV_PIX_FMT_ ## X: \
|
||||
c->lumToYV12 = ff_ ## x ## ToY_ ## opt; \
|
||||
if (!c->chrSrcHSubSample) \
|
||||
c->chrToYV12 = ff_ ## x ## ToUV_ ## opt; \
|
||||
break
|
||||
#define ASSIGN_SSE_SCALE_FUNC(hscalefn, filtersize, opt1, opt2) \
|
||||
switch (filtersize) { \
|
||||
case 4: ASSIGN_SCALE_FUNC2(hscalefn, 4, opt1, opt2); break; \
|
||||
case 8: ASSIGN_SCALE_FUNC2(hscalefn, 8, opt1, opt2); break; \
|
||||
default: if (filtersize & 4) ASSIGN_SCALE_FUNC2(hscalefn, X4, opt1, opt2); \
|
||||
else ASSIGN_SCALE_FUNC2(hscalefn, X8, opt1, opt2); \
|
||||
break; \
|
||||
}
|
||||
if (EXTERNAL_SSE2(cpu_flags)) {
|
||||
ASSIGN_SSE_SCALE_FUNC(c->hyScale, c->hLumFilterSize, sse2, sse2);
|
||||
ASSIGN_SSE_SCALE_FUNC(c->hcScale, c->hChrFilterSize, sse2, sse2);
|
||||
ASSIGN_VSCALEX_FUNC(c->yuv2planeX, sse2, ,
|
||||
HAVE_ALIGNED_STACK || ARCH_X86_64);
|
||||
if (!(c->opts.flags & SWS_ACCURATE_RND))
|
||||
ASSIGN_VSCALE_FUNC(c->yuv2plane1, sse2);
|
||||
|
||||
switch (c->opts.src_format) {
|
||||
case AV_PIX_FMT_YA8:
|
||||
c->lumToYV12 = ff_yuyvToY_sse2;
|
||||
if (c->needAlpha)
|
||||
c->alpToYV12 = ff_uyvyToY_sse2;
|
||||
break;
|
||||
case AV_PIX_FMT_YUYV422:
|
||||
c->lumToYV12 = ff_yuyvToY_sse2;
|
||||
c->chrToYV12 = ff_yuyvToUV_sse2;
|
||||
break;
|
||||
case AV_PIX_FMT_UYVY422:
|
||||
c->lumToYV12 = ff_uyvyToY_sse2;
|
||||
c->chrToYV12 = ff_uyvyToUV_sse2;
|
||||
break;
|
||||
case AV_PIX_FMT_NV12:
|
||||
c->chrToYV12 = ff_nv12ToUV_sse2;
|
||||
break;
|
||||
case AV_PIX_FMT_NV21:
|
||||
c->chrToYV12 = ff_nv21ToUV_sse2;
|
||||
break;
|
||||
case_rgb(rgb24, RGB24, sse2);
|
||||
case_rgb(bgr24, BGR24, sse2);
|
||||
case_rgb(bgra, BGRA, sse2);
|
||||
case_rgb(rgba, RGBA, sse2);
|
||||
case_rgb(abgr, ABGR, sse2);
|
||||
case_rgb(argb, ARGB, sse2);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (EXTERNAL_SSSE3(cpu_flags)) {
|
||||
ASSIGN_SSE_SCALE_FUNC(c->hyScale, c->hLumFilterSize, ssse3, ssse3);
|
||||
ASSIGN_SSE_SCALE_FUNC(c->hcScale, c->hChrFilterSize, ssse3, ssse3);
|
||||
switch (c->opts.src_format) {
|
||||
case_rgb(rgb24, RGB24, ssse3);
|
||||
case_rgb(bgr24, BGR24, ssse3);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (EXTERNAL_SSE4(cpu_flags)) {
|
||||
/* Xto15 don't need special sse4 functions */
|
||||
ASSIGN_SSE_SCALE_FUNC(c->hyScale, c->hLumFilterSize, sse4, ssse3);
|
||||
ASSIGN_SSE_SCALE_FUNC(c->hcScale, c->hChrFilterSize, sse4, ssse3);
|
||||
ASSIGN_VSCALEX_FUNC(c->yuv2planeX, sse4,
|
||||
if (!isBE(c->opts.dst_format)) c->yuv2planeX = ff_yuv2planeX_16_sse4,
|
||||
HAVE_ALIGNED_STACK || ARCH_X86_64);
|
||||
if (c->dstBpc == 16 && !isBE(c->opts.dst_format) && !(c->opts.flags & SWS_ACCURATE_RND))
|
||||
c->yuv2plane1 = ff_yuv2plane1_16_sse4;
|
||||
}
|
||||
|
||||
if (EXTERNAL_AVX(cpu_flags)) {
|
||||
ASSIGN_VSCALEX_FUNC(c->yuv2planeX, avx, ,
|
||||
HAVE_ALIGNED_STACK || ARCH_X86_64);
|
||||
if (!(c->opts.flags & SWS_ACCURATE_RND))
|
||||
ASSIGN_VSCALE_FUNC(c->yuv2plane1, avx);
|
||||
|
||||
switch (c->opts.src_format) {
|
||||
case AV_PIX_FMT_YUYV422:
|
||||
c->chrToYV12 = ff_yuyvToUV_avx;
|
||||
break;
|
||||
case AV_PIX_FMT_UYVY422:
|
||||
c->chrToYV12 = ff_uyvyToUV_avx;
|
||||
break;
|
||||
case AV_PIX_FMT_NV12:
|
||||
c->chrToYV12 = ff_nv12ToUV_avx;
|
||||
break;
|
||||
case AV_PIX_FMT_NV21:
|
||||
c->chrToYV12 = ff_nv21ToUV_avx;
|
||||
break;
|
||||
case_rgb(rgb24, RGB24, avx);
|
||||
case_rgb(bgr24, BGR24, avx);
|
||||
case_rgb(bgra, BGRA, avx);
|
||||
case_rgb(rgba, RGBA, avx);
|
||||
case_rgb(abgr, ABGR, avx);
|
||||
case_rgb(argb, ARGB, avx);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if ARCH_X86_64
|
||||
#define ASSIGN_AVX2_SCALE_FUNC(hscalefn, filtersize) \
|
||||
switch (filtersize) { \
|
||||
case 4: hscalefn = ff_hscale8to15_4_avx2; break; \
|
||||
default: hscalefn = ff_hscale8to15_X4_avx2; break; \
|
||||
break; \
|
||||
}
|
||||
|
||||
if (EXTERNAL_AVX2_FAST(cpu_flags) && !(cpu_flags & AV_CPU_FLAG_SLOW_GATHER)) {
|
||||
if ((c->srcBpc == 8) && (c->dstBpc <= 14)) {
|
||||
ASSIGN_AVX2_SCALE_FUNC(c->hcScale, c->hChrFilterSize);
|
||||
ASSIGN_AVX2_SCALE_FUNC(c->hyScale, c->hLumFilterSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (EXTERNAL_AVX2_FAST(cpu_flags)) {
|
||||
if (ARCH_X86_64)
|
||||
switch (c->opts.src_format) {
|
||||
case_rgb(rgb24, RGB24, avx2);
|
||||
case_rgb(bgr24, BGR24, avx2);
|
||||
case_rgb(bgra, BGRA, avx2);
|
||||
case_rgb(rgba, RGBA, avx2);
|
||||
case_rgb(abgr, ABGR, avx2);
|
||||
case_rgb(argb, ARGB, avx2);
|
||||
}
|
||||
if (!(c->opts.flags & SWS_ACCURATE_RND)) // FIXME
|
||||
switch (c->opts.dst_format) {
|
||||
case AV_PIX_FMT_NV12:
|
||||
case AV_PIX_FMT_NV24:
|
||||
c->yuv2nv12cX = ff_yuv2nv12cX_avx2;
|
||||
break;
|
||||
case AV_PIX_FMT_NV21:
|
||||
case AV_PIX_FMT_NV42:
|
||||
c->yuv2nv12cX = ff_yuv2nv21cX_avx2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(fmt, name, opt) \
|
||||
case fmt: \
|
||||
c->readAlpPlanar = ff_planar_##name##_to_a_##opt;
|
||||
|
||||
#define INPUT_PLANER_RGBA_YUV_FUNC_CASE(rgb_fmt, rgba_fmt, name, opt) \
|
||||
case rgba_fmt: \
|
||||
case rgb_fmt: \
|
||||
c->readLumPlanar = ff_planar_##name##_to_y_##opt; \
|
||||
c->readChrPlanar = ff_planar_##name##_to_uv_##opt; \
|
||||
break;
|
||||
|
||||
#define INPUT_PLANER_RGB_YUV_FUNC_CASE(fmt, name, opt) \
|
||||
case fmt: \
|
||||
c->readLumPlanar = ff_planar_##name##_to_y_##opt; \
|
||||
c->readChrPlanar = ff_planar_##name##_to_uv_##opt; \
|
||||
break;
|
||||
|
||||
#define INPUT_PLANER_RGB_UV_FUNC_CASE(fmt, name, opt) \
|
||||
case fmt: \
|
||||
c->readChrPlanar = ff_planar_##name##_to_uv_##opt; \
|
||||
break;
|
||||
|
||||
#define INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(rgb_fmt, rgba_fmt, name, opt) \
|
||||
INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(rgba_fmt##LE, name##le, opt) \
|
||||
INPUT_PLANER_RGB_YUV_FUNC_CASE(rgb_fmt##LE, name##le, opt) \
|
||||
INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(rgba_fmt##BE, name##be, opt) \
|
||||
INPUT_PLANER_RGB_YUV_FUNC_CASE(rgb_fmt##BE, name##be, opt)
|
||||
|
||||
#define INPUT_PLANER_RGBAXX_UVA_FUNC_CASE(rgb_fmt, rgba_fmt, name, opt) \
|
||||
INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(rgba_fmt##LE, name##le, opt) \
|
||||
INPUT_PLANER_RGB_UV_FUNC_CASE(rgb_fmt##LE, name##le, opt) \
|
||||
INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(rgba_fmt##BE, name##be, opt) \
|
||||
INPUT_PLANER_RGB_UV_FUNC_CASE(rgb_fmt##BE, name##be, opt)
|
||||
|
||||
#define INPUT_PLANER_RGBAXX_YUV_FUNC_CASE(rgb_fmt, rgba_fmt, name, opt) \
|
||||
INPUT_PLANER_RGBA_YUV_FUNC_CASE(rgb_fmt##LE, rgba_fmt##LE, name##le, opt) \
|
||||
INPUT_PLANER_RGBA_YUV_FUNC_CASE(rgb_fmt##BE, rgba_fmt##BE, name##be, opt)
|
||||
|
||||
#define INPUT_PLANER_RGBXX_YUV_FUNC_CASE(rgb_fmt, name, opt) \
|
||||
INPUT_PLANER_RGB_YUV_FUNC_CASE(rgb_fmt##LE, name##le, opt) \
|
||||
INPUT_PLANER_RGB_YUV_FUNC_CASE(rgb_fmt##BE, name##be, opt)
|
||||
|
||||
#define INPUT_PLANER_RGBXX_UV_FUNC_CASE(rgb_fmt, name, opt) \
|
||||
INPUT_PLANER_RGB_UV_FUNC_CASE(rgb_fmt##LE, name##le, opt) \
|
||||
INPUT_PLANER_RGB_UV_FUNC_CASE(rgb_fmt##BE, name##be, opt)
|
||||
|
||||
#define INPUT_PLANER_RGB_YUVA_ALL_CASES(opt) \
|
||||
INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(AV_PIX_FMT_GBRAP, rgb, opt) \
|
||||
INPUT_PLANER_RGB_YUV_FUNC_CASE( AV_PIX_FMT_GBRP, rgb, opt) \
|
||||
INPUT_PLANER_RGBXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP9, rgb9, opt) \
|
||||
INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, rgb10, opt) \
|
||||
INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, rgb12, opt) \
|
||||
INPUT_PLANER_RGBXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP14, rgb14, opt) \
|
||||
INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, rgb16, opt) \
|
||||
INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32, rgbf32, opt)
|
||||
|
||||
|
||||
if (EXTERNAL_SSE2(cpu_flags)) {
|
||||
switch (c->opts.src_format) {
|
||||
INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(AV_PIX_FMT_GBRAP, rgb, sse2);
|
||||
INPUT_PLANER_RGB_UV_FUNC_CASE( AV_PIX_FMT_GBRP, rgb, sse2);
|
||||
INPUT_PLANER_RGBXX_UV_FUNC_CASE( AV_PIX_FMT_GBRP9, rgb9, sse2);
|
||||
INPUT_PLANER_RGBAXX_UVA_FUNC_CASE( AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, rgb10, sse2);
|
||||
INPUT_PLANER_RGBAXX_UVA_FUNC_CASE( AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, rgb12, sse2);
|
||||
INPUT_PLANER_RGBXX_UV_FUNC_CASE( AV_PIX_FMT_GBRP14, rgb14, sse2);
|
||||
INPUT_PLANER_RGBAXX_UVA_FUNC_CASE( AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, rgb16, sse2);
|
||||
INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32, rgbf32, sse2);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (EXTERNAL_SSE4(cpu_flags)) {
|
||||
switch (c->opts.src_format) {
|
||||
case AV_PIX_FMT_GBRAP:
|
||||
INPUT_PLANER_RGB_YUV_FUNC_CASE( AV_PIX_FMT_GBRP, rgb, sse4);
|
||||
INPUT_PLANER_RGBXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP9, rgb9, sse4);
|
||||
INPUT_PLANER_RGBAXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, rgb10, sse4);
|
||||
INPUT_PLANER_RGBAXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, rgb12, sse4);
|
||||
INPUT_PLANER_RGBXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP14, rgb14, sse4);
|
||||
INPUT_PLANER_RGBAXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, rgb16, sse4);
|
||||
INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32, rgbf32, sse4);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (EXTERNAL_AVX2_FAST(cpu_flags)) {
|
||||
switch (c->opts.src_format) {
|
||||
INPUT_PLANER_RGB_YUVA_ALL_CASES(avx2)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(c->opts.flags & SWS_FULL_CHR_H_INT) {
|
||||
|
||||
#define YUV2ANYX_FUNC_CASE(fmt, name, opt) \
|
||||
case fmt: \
|
||||
c->yuv2anyX = ff_yuv2##name##_full_X_##opt; \
|
||||
break;
|
||||
|
||||
#define YUV2ANYX_GBRAP_CASES(opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP, gbrp, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP, gbrap, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP9LE, gbrp9le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP10LE, gbrp10le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP10LE, gbrap10le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP12LE, gbrp12le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP12LE, gbrap12le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP14LE, gbrp14le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP16LE, gbrp16le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP16LE, gbrap16le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRPF32LE, gbrpf32le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAPF32LE, gbrapf32le, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP9BE, gbrp9be, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP10BE, gbrp10be, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP10BE, gbrap10be, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP12BE, gbrp12be, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP12BE, gbrap12be, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP14BE, gbrp14be, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP16BE, gbrp16be, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP16BE, gbrap16be, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRPF32BE, gbrpf32be, opt) \
|
||||
YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAPF32BE, gbrapf32be, opt)
|
||||
|
||||
if (EXTERNAL_SSE2(cpu_flags)) {
|
||||
switch (c->opts.dst_format) {
|
||||
YUV2ANYX_GBRAP_CASES(sse2)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (EXTERNAL_SSE4(cpu_flags)) {
|
||||
switch (c->opts.dst_format) {
|
||||
YUV2ANYX_GBRAP_CASES(sse4)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (EXTERNAL_AVX2_FAST(cpu_flags)) {
|
||||
switch (c->opts.dst_format) {
|
||||
YUV2ANYX_GBRAP_CASES(avx2)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* check XMM registers for clobbers on Win64
|
||||
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
|
||||
*
|
||||
* 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/w64xmmtest.h"
|
||||
#include "libswscale/swscale.h"
|
||||
|
||||
wrap(sws_scale(SwsContext *c, const uint8_t *const srcSlice[],
|
||||
const int srcStride[], int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[]))
|
||||
{
|
||||
testxmmclobbers(sws_scale, c, srcSlice, srcStride, srcSliceY,
|
||||
srcSliceH, dst, dstStride);
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* software YUV to RGB converter
|
||||
*
|
||||
* Copyright (C) 2001-2007 Michael Niedermayer
|
||||
* Copyright (C) 2009-2010 Konstantin Shishkov
|
||||
*
|
||||
* MMX/MMXEXT template stuff (needed for fast movntq support),
|
||||
* 1,4,8bpp support and context / deglobalize stuff
|
||||
* by 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "libswscale/rgb2rgb.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libswscale/swscale_internal.h"
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavutil/x86/asm.h"
|
||||
#include "libavutil/x86/cpu.h"
|
||||
#include "libavutil/cpu.h"
|
||||
|
||||
#if HAVE_X86ASM
|
||||
|
||||
#define YUV2RGB_LOOP(depth) \
|
||||
h_size = (c->opts.dst_w + 7) & ~7; \
|
||||
if (h_size * depth > FFABS(dstStride[0])) \
|
||||
h_size -= 8; \
|
||||
\
|
||||
vshift = c->opts.src_format != AV_PIX_FMT_YUV422P; \
|
||||
\
|
||||
for (y = 0; y < srcSliceH; y++) { \
|
||||
uint8_t *image = dst[0] + (y + srcSliceY) * dstStride[0]; \
|
||||
const uint8_t *py = src[0] + y * srcStride[0]; \
|
||||
const uint8_t *pu = src[1] + (y >> vshift) * srcStride[1]; \
|
||||
const uint8_t *pv = src[2] + (y >> vshift) * srcStride[2]; \
|
||||
x86_reg index = -h_size / 2; \
|
||||
|
||||
extern void ff_yuv_420_rgb24_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
|
||||
const uint8_t *pv_index, const uint64_t *pointer_c_dither,
|
||||
const uint8_t *py_2index);
|
||||
extern void ff_yuv_420_bgr24_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
|
||||
const uint8_t *pv_index, const uint64_t *pointer_c_dither,
|
||||
const uint8_t *py_2index);
|
||||
|
||||
extern void ff_yuv_420_rgb15_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
|
||||
const uint8_t *pv_index, const uint64_t *pointer_c_dither,
|
||||
const uint8_t *py_2index);
|
||||
extern void ff_yuv_420_rgb16_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
|
||||
const uint8_t *pv_index, const uint64_t *pointer_c_dither,
|
||||
const uint8_t *py_2index);
|
||||
extern void ff_yuv_420_rgb32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
|
||||
const uint8_t *pv_index, const uint64_t *pointer_c_dither,
|
||||
const uint8_t *py_2index);
|
||||
extern void ff_yuv_420_bgr32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
|
||||
const uint8_t *pv_index, const uint64_t *pointer_c_dither,
|
||||
const uint8_t *py_2index);
|
||||
extern void ff_yuva_420_rgb32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
|
||||
const uint8_t *pv_index, const uint64_t *pointer_c_dither,
|
||||
const uint8_t *py_2index, const uint8_t *pa_2index);
|
||||
extern void ff_yuva_420_bgr32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
|
||||
const uint8_t *pv_index, const uint64_t *pointer_c_dither,
|
||||
const uint8_t *py_2index, const uint8_t *pa_2index);
|
||||
#if ARCH_X86_64
|
||||
extern void ff_yuv_420_gbrp24_ssse3(x86_reg index, uint8_t *image, uint8_t *dst_b, uint8_t *dst_r,
|
||||
const uint8_t *pu_index, const uint8_t *pv_index,
|
||||
const uint64_t *pointer_c_dither,
|
||||
const uint8_t *py_2index);
|
||||
#endif
|
||||
|
||||
static inline int yuv420_rgb15_ssse3(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[],
|
||||
int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
int y, h_size, vshift;
|
||||
|
||||
YUV2RGB_LOOP(2)
|
||||
|
||||
c->blueDither = ff_dither8[y & 1];
|
||||
c->greenDither = ff_dither8[y & 1];
|
||||
c->redDither = ff_dither8[(y + 1) & 1];
|
||||
|
||||
ff_yuv_420_rgb15_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
|
||||
}
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
static inline int yuv420_rgb16_ssse3(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[],
|
||||
int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
int y, h_size, vshift;
|
||||
|
||||
YUV2RGB_LOOP(2)
|
||||
|
||||
c->blueDither = ff_dither8[y & 1];
|
||||
c->greenDither = ff_dither4[y & 1];
|
||||
c->redDither = ff_dither8[(y + 1) & 1];
|
||||
|
||||
ff_yuv_420_rgb16_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
|
||||
}
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
static inline int yuv420_rgb32_ssse3(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[],
|
||||
int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
int y, h_size, vshift;
|
||||
|
||||
YUV2RGB_LOOP(4)
|
||||
|
||||
ff_yuv_420_rgb32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
|
||||
}
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
static inline int yuv420_bgr32_ssse3(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[],
|
||||
int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
int y, h_size, vshift;
|
||||
|
||||
YUV2RGB_LOOP(4)
|
||||
|
||||
ff_yuv_420_bgr32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
|
||||
}
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
static inline int yuva420_rgb32_ssse3(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[],
|
||||
int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
int y, h_size, vshift;
|
||||
YUV2RGB_LOOP(4)
|
||||
|
||||
const uint8_t *pa = src[3] + y * srcStride[3];
|
||||
ff_yuva_420_rgb32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index, pa - 2 * index);
|
||||
}
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
static inline int yuva420_bgr32_ssse3(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[],
|
||||
int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
int y, h_size, vshift;
|
||||
|
||||
YUV2RGB_LOOP(4)
|
||||
|
||||
const uint8_t *pa = src[3] + y * srcStride[3];
|
||||
ff_yuva_420_bgr32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index, pa - 2 * index);
|
||||
}
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
static inline int yuv420_rgb24_ssse3(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[],
|
||||
int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
int y, h_size, vshift;
|
||||
|
||||
YUV2RGB_LOOP(3)
|
||||
|
||||
ff_yuv_420_rgb24_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
|
||||
}
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
static inline int yuv420_bgr24_ssse3(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[],
|
||||
int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
int y, h_size, vshift;
|
||||
|
||||
YUV2RGB_LOOP(3)
|
||||
|
||||
ff_yuv_420_bgr24_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
|
||||
}
|
||||
return srcSliceH;
|
||||
}
|
||||
|
||||
#if ARCH_X86_64
|
||||
static inline int yuv420_gbrp_ssse3(SwsInternal *c, const uint8_t *const src[],
|
||||
const int srcStride[],
|
||||
int srcSliceY, int srcSliceH,
|
||||
uint8_t *const dst[], const int dstStride[])
|
||||
{
|
||||
int y, h_size, vshift;
|
||||
|
||||
h_size = (c->opts.dst_w + 7) & ~7;
|
||||
if (h_size * 3 > FFABS(dstStride[0]))
|
||||
h_size -= 8;
|
||||
|
||||
vshift = c->opts.src_format != AV_PIX_FMT_YUV422P;
|
||||
|
||||
for (y = 0; y < srcSliceH; y++) {
|
||||
uint8_t *dst_g = dst[0] + (y + srcSliceY) * dstStride[0];
|
||||
uint8_t *dst_b = dst[1] + (y + srcSliceY) * dstStride[1];
|
||||
uint8_t *dst_r = dst[2] + (y + srcSliceY) * dstStride[2];
|
||||
const uint8_t *py = src[0] + y * srcStride[0];
|
||||
const uint8_t *pu = src[1] + (y >> vshift) * srcStride[1];
|
||||
const uint8_t *pv = src[2] + (y >> vshift) * srcStride[2];
|
||||
x86_reg index = -h_size / 2;
|
||||
|
||||
ff_yuv_420_gbrp24_ssse3(index, dst_g, dst_b, dst_r, pu - index, pv - index, &(c->redDither), py - 2 * index);
|
||||
}
|
||||
return srcSliceH;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_X86ASM */
|
||||
|
||||
av_cold SwsFunc ff_yuv2rgb_init_x86(SwsInternal *c)
|
||||
{
|
||||
#if HAVE_X86ASM
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
if (EXTERNAL_SSSE3(cpu_flags)) {
|
||||
switch (c->opts.dst_format) {
|
||||
case AV_PIX_FMT_RGB32:
|
||||
if (c->opts.src_format == AV_PIX_FMT_YUVA420P) {
|
||||
#if CONFIG_SWSCALE_ALPHA
|
||||
return yuva420_rgb32_ssse3;
|
||||
#endif
|
||||
break;
|
||||
} else
|
||||
return yuv420_rgb32_ssse3;
|
||||
case AV_PIX_FMT_BGR32:
|
||||
if (c->opts.src_format == AV_PIX_FMT_YUVA420P) {
|
||||
#if CONFIG_SWSCALE_ALPHA
|
||||
return yuva420_bgr32_ssse3;
|
||||
#endif
|
||||
break;
|
||||
} else
|
||||
return yuv420_bgr32_ssse3;
|
||||
case AV_PIX_FMT_RGB24:
|
||||
return yuv420_rgb24_ssse3;
|
||||
case AV_PIX_FMT_BGR24:
|
||||
return yuv420_bgr24_ssse3;
|
||||
case AV_PIX_FMT_RGB565:
|
||||
return yuv420_rgb16_ssse3;
|
||||
case AV_PIX_FMT_RGB555:
|
||||
return yuv420_rgb15_ssse3;
|
||||
#if ARCH_X86_64
|
||||
case AV_PIX_FMT_GBRP:
|
||||
return yuv420_gbrp_ssse3;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_X86ASM */
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
;******************************************************************************
|
||||
;* 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
|
||||
%define unroll 1
|
||||
%else
|
||||
%define movr movdqu
|
||||
%define unroll 2
|
||||
%endif
|
||||
movsxdifnidn dstWq, dstWd
|
||||
movsxdifnidn offsetq, offsetd
|
||||
movsxdifnidn srcq, srcd
|
||||
%if cpuflag(avx2)
|
||||
vpbroadcastq m3, [ditherq]
|
||||
%else
|
||||
movq xm3, [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
|
||||
movd xm1, filterSized
|
||||
SPLATW m1, xm1, 0
|
||||
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
|
||||
%if cpuflag(sse3)
|
||||
mova m6, m7
|
||||
mova m1, m7
|
||||
%endif
|
||||
.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
|
||||
%if cpuflag(sse3)
|
||||
pmulhw m2, m0, [srcq + offsetq * 2 + 2 * mmsize]
|
||||
pmulhw m5, m0, [srcq + offsetq * 2 + 3 * mmsize]
|
||||
paddw m6, m6, m2
|
||||
paddw m1, m1, m5
|
||||
%endif
|
||||
add filterSizeq, $10
|
||||
mov srcq, [filterSizeq]
|
||||
test srcq, srcq
|
||||
jnz .loop
|
||||
psraw m3, m3, 3
|
||||
psraw m4, m4, 3
|
||||
%if cpuflag(sse3)
|
||||
psraw m6, m6, 3
|
||||
psraw m1, m1, 3
|
||||
%endif
|
||||
packuswb m3, m3, m4
|
||||
%if cpuflag(sse3)
|
||||
packuswb m6, m6, m1
|
||||
%endif
|
||||
mov srcq, [filterq]
|
||||
%if cpuflag(avx2)
|
||||
vpermq m3, m3, 216
|
||||
vpermq m6, m6, 216
|
||||
%endif
|
||||
movr [destq + offsetq], m3
|
||||
%if cpuflag(sse3)
|
||||
movr [destq + offsetq + mmsize], m6
|
||||
%endif
|
||||
add offsetq, mmsize * unroll
|
||||
mov filterSizeq, filterq
|
||||
cmp offsetq, dstWq
|
||||
jb .outerloop
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_MMX mmxext
|
||||
YUV2YUVX_FUNC
|
||||
INIT_XMM sse3
|
||||
YUV2YUVX_FUNC
|
||||
%if HAVE_AVX2_EXTERNAL
|
||||
INIT_YMM avx2
|
||||
YUV2YUVX_FUNC
|
||||
%endif
|
||||
@@ -0,0 +1,316 @@
|
||||
;******************************************************************************
|
||||
;* software YUV to RGB converter
|
||||
;*
|
||||
;* Copyright (C) 2001-2007 Michael Niedermayer
|
||||
;* (c) 2010 Konstantin Shishkov
|
||||
;*
|
||||
;* 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_RODATA
|
||||
|
||||
; below variables are named like mask_dwXY, which means to preserve dword No.X & No.Y
|
||||
mask_dw036 : db -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0
|
||||
mask_dw147 : db 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1
|
||||
mask_dw25 : db 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0
|
||||
rgb24_shuf1: db 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11
|
||||
rgb24_shuf2: db 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5
|
||||
rgb24_shuf3: db 4, 5, 10, 11, 0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15
|
||||
gbrp_shuf : db 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15
|
||||
pw_00ff: times 8 dw 255
|
||||
pb_f8: times 16 db 248
|
||||
pb_e0: times 16 db 224
|
||||
pb_03: times 16 db 3
|
||||
pb_07: times 16 db 7
|
||||
|
||||
SECTION .text
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
;
|
||||
; YUV420/YUVA420 to RGB/BGR 15/16/24/32
|
||||
; R = Y + ((vrCoff * (v - 128)) >> 8)
|
||||
; G = Y - ((ugCoff * (u - 128) + vgCoff * (v - 128)) >> 8)
|
||||
; B = Y + ((ubCoff * (u - 128)) >> 8)
|
||||
;
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
%macro yuv2rgb_fn 3
|
||||
|
||||
%if %3 == 32
|
||||
%ifidn %1, yuva
|
||||
%define parameters index, image, pu_index, pv_index, pointer_c_dither, py_2index, pa_2index
|
||||
%define GPR_num 7
|
||||
%else
|
||||
%define parameters index, image, pu_index, pv_index, pointer_c_dither, py_2index
|
||||
%define GPR_num 6
|
||||
%endif
|
||||
%else
|
||||
%ifidn %2, gbrp
|
||||
%define parameters index, image, dst_b, dst_r, pu_index, pv_index, pointer_c_dither, py_2index
|
||||
%define GPR_num 8
|
||||
%else
|
||||
%define parameters index, image, pu_index, pv_index, pointer_c_dither, py_2index
|
||||
%define GPR_num 6
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%define m_green m2
|
||||
%define m_alpha m3
|
||||
%define m_y m6
|
||||
%define m_u m0
|
||||
%define m_v m1
|
||||
%ifidn %2, rgb
|
||||
%define m_red m1
|
||||
%define m_blue m0
|
||||
%else
|
||||
%define m_red m0
|
||||
%define m_blue m1
|
||||
%endif
|
||||
|
||||
%define time_num 2
|
||||
%if ARCH_X86_32
|
||||
%define reg_num 8
|
||||
%define my_offset [pointer_c_ditherq + 8 * 8]
|
||||
%define mu_offset [pointer_c_ditherq + 9 * 8]
|
||||
%define mv_offset [pointer_c_ditherq + 10 * 8]
|
||||
%define mug_coff [pointer_c_ditherq + 7 * 8]
|
||||
%define mvg_coff [pointer_c_ditherq + 6 * 8]
|
||||
%define my_coff [pointer_c_ditherq + 3 * 8]
|
||||
%define mub_coff [pointer_c_ditherq + 5 * 8]
|
||||
%define mvr_coff [pointer_c_ditherq + 4 * 8]
|
||||
%else ; ARCH_X86_64
|
||||
%define reg_num 16
|
||||
%define y_offset m8
|
||||
%define u_offset m9
|
||||
%define v_offset m10
|
||||
%define ug_coff m11
|
||||
%define vg_coff m12
|
||||
%define y_coff m13
|
||||
%define ub_coff m14
|
||||
%define vr_coff m15
|
||||
%endif ; ARCH_X86_32/64
|
||||
|
||||
cglobal %1_420_%2%3, GPR_num, GPR_num, reg_num, parameters
|
||||
|
||||
%if ARCH_X86_64
|
||||
movsxd indexq, indexd
|
||||
VBROADCASTSD y_offset, [pointer_c_ditherq + 8 * 8]
|
||||
VBROADCASTSD u_offset, [pointer_c_ditherq + 9 * 8]
|
||||
VBROADCASTSD v_offset, [pointer_c_ditherq + 10 * 8]
|
||||
VBROADCASTSD ug_coff, [pointer_c_ditherq + 7 * 8]
|
||||
VBROADCASTSD vg_coff, [pointer_c_ditherq + 6 * 8]
|
||||
VBROADCASTSD y_coff, [pointer_c_ditherq + 3 * 8]
|
||||
VBROADCASTSD ub_coff, [pointer_c_ditherq + 5 * 8]
|
||||
VBROADCASTSD vr_coff, [pointer_c_ditherq + 4 * 8]
|
||||
%endif
|
||||
.loop0:
|
||||
movu m_y, [py_2indexq + 2 * indexq]
|
||||
movh m_u, [pu_indexq + indexq]
|
||||
movh m_v, [pv_indexq + indexq]
|
||||
pxor m4, m4
|
||||
mova m7, m6
|
||||
punpcklbw m0, m4
|
||||
punpcklbw m1, m4
|
||||
mova m2, [pw_00ff]
|
||||
pand m6, m2
|
||||
psrlw m7, 8
|
||||
psllw m0, 3
|
||||
psllw m1, 3
|
||||
psllw m6, 3
|
||||
psllw m7, 3
|
||||
%if ARCH_X86_32
|
||||
VBROADCASTSD m2, mu_offset
|
||||
VBROADCASTSD m3, mv_offset
|
||||
VBROADCASTSD m4, my_offset
|
||||
psubsw m0, m2 ; U = U - 128
|
||||
psubsw m1, m3 ; V = V - 128
|
||||
psubw m6, m4
|
||||
psubw m7, m4
|
||||
VBROADCASTSD m2, mug_coff
|
||||
VBROADCASTSD m3, mvg_coff
|
||||
VBROADCASTSD m4, my_coff
|
||||
VBROADCASTSD m5, mub_coff
|
||||
pmulhw m2, m0
|
||||
pmulhw m3, m1
|
||||
pmulhw m6, m4
|
||||
pmulhw m7, m4
|
||||
pmulhw m0, m5
|
||||
VBROADCASTSD m4, mvr_coff
|
||||
pmulhw m1, m4
|
||||
%else ; ARCH_X86_64
|
||||
psubsw m0, u_offset ; U = U - 128
|
||||
psubsw m1, v_offset ; V = V - 128
|
||||
psubw m6, y_offset
|
||||
psubw m7, y_offset
|
||||
mova m2, m0
|
||||
mova m3, m1
|
||||
pmulhw m2, ug_coff
|
||||
pmulhw m3, vg_coff
|
||||
pmulhw m6, y_coff
|
||||
pmulhw m7, y_coff
|
||||
pmulhw m0, ub_coff
|
||||
pmulhw m1, vr_coff
|
||||
%endif
|
||||
paddsw m2, m3
|
||||
mova m3, m7
|
||||
mova m5, m7
|
||||
paddsw m3, m0 ; B1 B3 B5 B7 ...
|
||||
paddsw m5, m1 ; R1 R3 R5 R7 ...
|
||||
paddsw m7, m2 ; G1 G3 G5 G7 ...
|
||||
paddsw m0, m6 ; B0 B2 B4 B6 ...
|
||||
paddsw m1, m6 ; R0 R2 R4 R6 ...
|
||||
paddsw m2, m6 ; G0 G2 G4 G6 ...
|
||||
|
||||
%if %3 == 24 ; PACK RGB24
|
||||
packuswb m0, m3 ; B0 B2 B4 B6 ... B1 B3 B5 B7 ...
|
||||
packuswb m1, m5 ; R0 R2 R4 R6 ... R1 R3 R5 R7 ...
|
||||
packuswb m2, m7 ; G0 G2 G4 G6 ... G1 G3 G5 G7 ...
|
||||
%ifidn %2, gbrp ; PLANAR GBRP
|
||||
%define depth 1
|
||||
mova m4, [gbrp_shuf]
|
||||
pshufb m0, m4
|
||||
pshufb m1, m4
|
||||
pshufb m2, m4
|
||||
movu [imageq], m2
|
||||
movu [dst_bq], m0
|
||||
movu [dst_rq], m1
|
||||
add dst_bq, 8 * depth * time_num
|
||||
add dst_rq, 8 * depth * time_num
|
||||
%else
|
||||
%define depth 3
|
||||
mova m3, m_red
|
||||
mova m6, m_blue
|
||||
psrldq m_red, 8
|
||||
punpcklbw m3, m2 ; R0 G0 R2 G2 R4 G4 R6 G6 R8 G8 ...
|
||||
punpcklbw m6, m_red ; B0 R1 B2 R3 B4 R5 B6 R7 B8 R9 ...
|
||||
punpckhbw m2, m_blue ; G1 B1 G3 B3 G5 B5 G7 B7 G9 B9 ...
|
||||
pshufb m3, [rgb24_shuf1] ; r0 g0 r6 g6 r12 g12 r2 g2 r8 g8 r14 g14 r4 g4 r10 g10
|
||||
pshufb m6, [rgb24_shuf2] ; b10 r11 b0 r1 b6 r7 b12 r13 b2 r3 b8 r9 b14 r15 b4 r5
|
||||
pshufb m2, [rgb24_shuf3] ; g5 b5 g11 b11 g1 b1 g7 b7 g13 b13 g3 b3 g9 b9 g15 b15
|
||||
mova m7, [mask_dw036]
|
||||
mova m4, [mask_dw147]
|
||||
mova m5, [mask_dw25]
|
||||
pand m0, m7, m3 ; r0 g0 --- --- --- --- r2 g2 --- --- --- --- r4 g4 --- ---
|
||||
pand m1, m4, m6 ; --- --- b0 r1 --- --- --- --- b2 r3 --- --- --- --- b4 r5
|
||||
por m0, m1
|
||||
pand m1, m5, m2 ; --- --- --- --- g1 b1 --- --- --- --- g3 b3 --- --- --- ---
|
||||
por m0, m1 ; r0 g0 b0 r1 g1 b1 r2 g2 b2 r3 g3 b3 r4 g4 b4 r5
|
||||
pand m1, m7, m2 ; g5 b5 --- --- --- --- g7 b7 --- --- --- --- g9 b9 --- ---
|
||||
pand m7, m6 ; b10 r11 --- --- --- --- b12 r13 --- --- --- --- b14 r15 --- ---
|
||||
pand m6, m5 ; --- --- --- --- b6 r7 --- --- --- --- b8 r9 --- --- --- ---
|
||||
por m1, m6
|
||||
pand m6, m4, m3 ; --- --- r6 g6 --- --- --- --- r8 g8 --- --- --- --- r10 g10
|
||||
pand m2, m4 ; --- --- g11 b11 --- --- --- --- g13 b13 --- --- --- --- g15 b15
|
||||
pand m3, m5 ; --- --- --- --- r12 g12 --- --- --- --- r14 g14 --- --- --- ---
|
||||
por m2, m7
|
||||
por m1, m6 ; g5 b5 r6 g6 b6 r7 g7 b7 r8 g8 b8 r9 g9 b9 r10 g10
|
||||
por m2, m3 ; b10 r11 g11 b11 r12 g12 b12 r13 g13 b13 r14 g14 b14 r15 g15 b15
|
||||
movu [imageq], m0
|
||||
movu [imageq + 16], m1
|
||||
movu [imageq + 32], m2
|
||||
%endif ; PLANAR GBRP
|
||||
%else ; PACK RGB15/16/32
|
||||
packuswb m0, m1
|
||||
packuswb m3, m5
|
||||
packuswb m2, m2
|
||||
mova m1, m0
|
||||
packuswb m7, m7
|
||||
punpcklbw m0, m3 ; B0 B1 B2 B3 ... B7
|
||||
punpckhbw m1, m3 ; R0 R1 R2 R3 ... R7
|
||||
punpcklbw m2, m7 ; G0 G1 G2 G3 ... G7
|
||||
%if %3 == 32 ; PACK RGB32
|
||||
%define depth 4
|
||||
%ifidn %1, yuv
|
||||
pcmpeqd m3, m3 ; Set alpha empty
|
||||
%else
|
||||
movu m3, [pa_2indexq + 2 * indexq] ; Load alpha
|
||||
%endif
|
||||
mova m5, m_blue
|
||||
mova m6, m_red
|
||||
punpckhbw m5, m_green
|
||||
punpcklbw m_blue, m_green
|
||||
punpckhbw m6, m_alpha
|
||||
punpcklbw m_red, m_alpha
|
||||
mova m_green, m_blue
|
||||
mova m_alpha, m5
|
||||
punpcklwd m_blue, m_red
|
||||
punpckhwd m_green, m_red
|
||||
punpcklwd m5, m6
|
||||
punpckhwd m_alpha, m6
|
||||
movu [imageq + 0], m_blue
|
||||
movu [imageq + 8 * time_num], m_green
|
||||
movu [imageq + 16 * time_num], m5
|
||||
movu [imageq + 24 * time_num], m_alpha
|
||||
%else ; PACK RGB15/16
|
||||
%define depth 2
|
||||
%define red_dither m3
|
||||
%define green_dither m4
|
||||
%define blue_dither m5
|
||||
VBROADCASTSD red_dither, [pointer_c_ditherq + 0 * 8]
|
||||
VBROADCASTSD green_dither, [pointer_c_ditherq + 1 * 8]
|
||||
VBROADCASTSD blue_dither, [pointer_c_ditherq + 2 * 8]
|
||||
%if %3 == 15
|
||||
%define gmask pb_03
|
||||
%define isRGB15 1
|
||||
%else
|
||||
%define gmask pb_07
|
||||
%define isRGB15 0
|
||||
%endif
|
||||
paddusb m0, blue_dither
|
||||
paddusb m2, green_dither
|
||||
paddusb m1, red_dither
|
||||
pand m0, [pb_f8]
|
||||
pand m1, [pb_f8]
|
||||
mova m3, m2
|
||||
psllw m2, 3 - isRGB15
|
||||
psrlw m3, 5 + isRGB15
|
||||
psrlw m0, 3
|
||||
psrlw m1, isRGB15
|
||||
pand m2, [pb_e0]
|
||||
pand m3, [gmask]
|
||||
por m0, m2
|
||||
por m1, m3
|
||||
mova m2, m0
|
||||
punpcklbw m0, m1
|
||||
punpckhbw m2, m1
|
||||
movu [imageq], m0
|
||||
movu [imageq + 8 * time_num], m2
|
||||
%endif ; PACK RGB15/16
|
||||
%endif ; PACK RGB15/16/32
|
||||
|
||||
add imageq, 8 * depth * time_num
|
||||
add indexq, 4 * time_num
|
||||
js .loop0
|
||||
|
||||
RET
|
||||
|
||||
%endmacro
|
||||
|
||||
INIT_XMM ssse3
|
||||
yuv2rgb_fn yuv, rgb, 24
|
||||
yuv2rgb_fn yuv, bgr, 24
|
||||
yuv2rgb_fn yuv, rgb, 32
|
||||
yuv2rgb_fn yuv, bgr, 32
|
||||
yuv2rgb_fn yuva, rgb, 32
|
||||
yuv2rgb_fn yuva, bgr, 32
|
||||
yuv2rgb_fn yuv, rgb, 15
|
||||
yuv2rgb_fn yuv, rgb, 16
|
||||
%if ARCH_X86_64
|
||||
yuv2rgb_fn yuv, gbrp, 24
|
||||
%endif
|
||||
Reference in New Issue
Block a user