This commit is contained in:
2025-08-27 15:09:05 +09:00
parent 57961d84de
commit a13f66d917
9896 changed files with 2193048 additions and 730 deletions
+18
View File
@@ -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
+973
View File
@@ -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
+201
View File
@@ -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
+411
View File
@@ -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
+389
View File
@@ -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
+156
View File
@@ -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
+854
View File
@@ -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
+31
View File
@@ -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);
}
+281
View File
@@ -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;
}
+134
View File
@@ -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
+316
View File
@@ -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