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
+11
View File
@@ -0,0 +1,11 @@
OBJS += aarch64/rgb2rgb.o \
aarch64/swscale.o \
aarch64/swscale_unscaled.o \
NEON-OBJS += aarch64/hscale.o \
aarch64/input.o \
aarch64/output.o \
aarch64/range_convert_neon.o \
aarch64/rgb2rgb_neon.o \
aarch64/swscale_unscaled_neon.o \
aarch64/yuv2rgb_neon.o \
File diff suppressed because it is too large Load Diff
+403
View File
@@ -0,0 +1,403 @@
/*
* Copyright (c) 2024 Zhao Zhili <quinkblack@foxmail.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/aarch64/asm.S"
.macro rgb_to_yuv_load_rgb src, element=3
.if \element == 3
ld3 { v16.16b, v17.16b, v18.16b }, [\src]
.else
ld4 { v16.16b, v17.16b, v18.16b, v19.16b }, [\src]
.endif
uxtl v19.8h, v16.8b // v19: r
uxtl v20.8h, v17.8b // v20: g
uxtl v21.8h, v18.8b // v21: b
uxtl2 v22.8h, v16.16b // v22: r
uxtl2 v23.8h, v17.16b // v23: g
uxtl2 v24.8h, v18.16b // v24: b
.endm
.macro argb_to_yuv_load_rgb src
ld4 { v16.16b, v17.16b, v18.16b, v19.16b }, [\src]
uxtl v21.8h, v19.8b // v21: b
uxtl2 v24.8h, v19.16b // v24: b
uxtl v19.8h, v17.8b // v19: r
uxtl v20.8h, v18.8b // v20: g
uxtl2 v22.8h, v17.16b // v22: r
uxtl2 v23.8h, v18.16b // v23: g
.endm
.macro rgb_to_yuv_product r, g, b, dst1, dst2, dst, coef0, coef1, coef2, right_shift
mov \dst1\().16b, v6.16b // dst1 = const_offset
mov \dst2\().16b, v6.16b // dst2 = const_offset
smlal \dst1\().4s, \coef0\().4h, \r\().4h // dst1 += rx * r
smlal \dst1\().4s, \coef1\().4h, \g\().4h // dst1 += gx * g
smlal \dst1\().4s, \coef2\().4h, \b\().4h // dst1 += bx * b
smlal2 \dst2\().4s, \coef0\().8h, \r\().8h // dst2 += rx * r
smlal2 \dst2\().4s, \coef1\().8h, \g\().8h // dst2 += gx * g
smlal2 \dst2\().4s, \coef2\().8h, \b\().8h // dst2 += bx * b
sqshrn \dst\().4h, \dst1\().4s, \right_shift // dst_lower_half = dst1 >> right_shift
sqshrn2 \dst\().8h, \dst2\().4s, \right_shift // dst_higher_half = dst2 >> right_shift
.endm
.macro rgbToY_neon fmt_bgr, fmt_rgb, element, alpha_first=0
function ff_\fmt_bgr\()ToY_neon, export=1
cmp w4, #0 // check width > 0
ldp w12, w11, [x5] // w12: ry, w11: gy
ldr w10, [x5, #8] // w10: by
b.gt 4f
ret
endfunc
function ff_\fmt_rgb\()ToY_neon, export=1
cmp w4, #0 // check width > 0
ldp w10, w11, [x5] // w10: ry, w11: gy
ldr w12, [x5, #8] // w12: by
b.le 3f
4:
mov w9, #256 // w9 = 1 << (RGB2YUV_SHIFT - 7)
movk w9, #8, lsl #16 // w9 += 32 << (RGB2YUV_SHIFT - 1)
dup v6.4s, w9 // w9: const_offset
cmp w4, #16
dup v0.8h, w10
dup v1.8h, w11
dup v2.8h, w12
b.lt 2f
1:
.if \alpha_first
argb_to_yuv_load_rgb x1
.else
rgb_to_yuv_load_rgb x1, \element
.endif
rgb_to_yuv_product v19, v20, v21, v25, v26, v16, v0, v1, v2, #9
rgb_to_yuv_product v22, v23, v24, v27, v28, v17, v0, v1, v2, #9
sub w4, w4, #16 // width -= 16
add x1, x1, #(16*\element)
cmp w4, #16 // width >= 16 ?
stp q16, q17, [x0], #32 // store to dst
b.ge 1b
cbz x4, 3f
2:
.if \alpha_first
ldrb w13, [x1, #1] // w13: r
ldrb w14, [x1, #2] // w14: g
ldrb w15, [x1, #3] // w15: b
.else
ldrb w13, [x1] // w13: r
ldrb w14, [x1, #1] // w14: g
ldrb w15, [x1, #2] // w15: b
.endif
smaddl x13, w13, w10, x9 // x13 = ry * r + const_offset
smaddl x13, w14, w11, x13 // x13 += gy * g
smaddl x13, w15, w12, x13 // x13 += by * b
asr w13, w13, #9 // x13 >>= 9
sub w4, w4, #1 // width--
add x1, x1, #\element
strh w13, [x0], #2 // store to dst
cbnz w4, 2b
3:
ret
endfunc
.endm
rgbToY_neon bgr24, rgb24, element=3
rgbToY_neon bgra32, rgba32, element=4
rgbToY_neon abgr32, argb32, element=4, alpha_first=1
.macro rgb_set_uv_coeff half
.if \half
mov w9, #512
movk w9, #128, lsl #16 // w9: const_offset
.else
mov w9, #256
movk w9, #64, lsl #16 // w9: const_offset
.endif
dup v0.8h, w10
dup v1.8h, w11
dup v2.8h, w12
dup v3.8h, w13
dup v4.8h, w14
dup v5.8h, w15
dup v6.4s, w9
.endm
.macro rgb_load_add_half off_r1, off_r2, off_g1, off_g2, off_b1, off_b2
ldrb w2, [x3, #\off_r1] // w2: r1
ldrb w4, [x3, #\off_r2] // w4: r2
add w2, w2, w4 // w2 = r1 + r2
ldrb w4, [x3, #\off_g1] // w4: g1
ldrb w7, [x3, #\off_g2] // w7: g2
add w4, w4, w7 // w4 = g1 + g2
ldrb w7, [x3, #\off_b1] // w7: b1
ldrb w8, [x3, #\off_b2] // w8: b2
add w7, w7, w8 // w7 = b1 + b2
.endm
.macro rgbToUV_half_neon fmt_bgr, fmt_rgb, element, alpha_first=0
function ff_\fmt_bgr\()ToUV_half_neon, export=1
cmp w5, #0 // check width > 0
b.le 3f
ldp w12, w11, [x6, #12]
ldp w10, w15, [x6, #20]
ldp w14, w13, [x6, #28]
b 4f
endfunc
function ff_\fmt_rgb\()ToUV_half_neon, export=1
cmp w5, #0 // check width > 0
b.le 3f
ldp w10, w11, [x6, #12] // w10: ru, w11: gu
ldp w12, w13, [x6, #20] // w12: bu, w13: rv
ldp w14, w15, [x6, #28] // w14: gv, w15: bv
4:
cmp w5, #8
rgb_set_uv_coeff half=1
b.lt 2f
1:
.if \element == 3
ld3 { v16.16b, v17.16b, v18.16b }, [x3]
.else
ld4 { v16.16b, v17.16b, v18.16b, v19.16b }, [x3]
.endif
.if \alpha_first
uaddlp v21.8h, v19.16b
uaddlp v20.8h, v18.16b
uaddlp v19.8h, v17.16b
.else
uaddlp v19.8h, v16.16b // v19: r
uaddlp v20.8h, v17.16b // v20: g
uaddlp v21.8h, v18.16b // v21: b
.endif
rgb_to_yuv_product v19, v20, v21, v22, v23, v16, v0, v1, v2, #10
rgb_to_yuv_product v19, v20, v21, v24, v25, v17, v3, v4, v5, #10
sub w5, w5, #8 // width -= 8
add x3, x3, #(16*\element)
cmp w5, #8 // width >= 8 ?
str q16, [x0], #16 // store dst_u
str q17, [x1], #16 // store dst_v
b.ge 1b
cbz w5, 3f
2:
.if \alpha_first
rgb_load_add_half 1, 5, 2, 6, 3, 7
.else
.if \element == 3
rgb_load_add_half 0, 3, 1, 4, 2, 5
.else
rgb_load_add_half 0, 4, 1, 5, 2, 6
.endif
.endif
smaddl x8, w2, w10, x9 // dst_u = ru * r + const_offset
smaddl x8, w4, w11, x8 // dst_u += gu * g
smaddl x8, w7, w12, x8 // dst_u += bu * b
asr x8, x8, #10 // dst_u >>= 10
strh w8, [x0], #2 // store dst_u
smaddl x8, w2, w13, x9 // dst_v = rv * r + const_offset
smaddl x8, w4, w14, x8 // dst_v += gv * g
smaddl x8, w7, w15, x8 // dst_v += bv * b
asr x8, x8, #10 // dst_v >>= 10
sub w5, w5, #1
add x3, x3, #(2*\element)
strh w8, [x1], #2 // store dst_v
cbnz w5, 2b
3:
ret
endfunc
.endm
rgbToUV_half_neon bgr24, rgb24, element=3
rgbToUV_half_neon bgra32, rgba32, element=4
rgbToUV_half_neon abgr32, argb32, element=4, alpha_first=1
.macro rgbToUV_neon fmt_bgr, fmt_rgb, element, alpha_first=0
function ff_\fmt_bgr\()ToUV_neon, export=1
cmp w5, #0 // check width > 0
b.le 3f
ldp w12, w11, [x6, #12]
ldp w10, w15, [x6, #20]
ldp w14, w13, [x6, #28]
b 4f
endfunc
function ff_\fmt_rgb\()ToUV_neon, export=1
cmp w5, #0 // check width > 0
b.le 3f
ldp w10, w11, [x6, #12] // w10: ru, w11: gu
ldp w12, w13, [x6, #20] // w12: bu, w13: rv
ldp w14, w15, [x6, #28] // w14: gv, w15: bv
4:
cmp w5, #16
rgb_set_uv_coeff half=0
b.lt 2f
1:
.if \alpha_first
argb_to_yuv_load_rgb x3
.else
rgb_to_yuv_load_rgb x3, \element
.endif
rgb_to_yuv_product v19, v20, v21, v25, v26, v16, v0, v1, v2, #9
rgb_to_yuv_product v22, v23, v24, v27, v28, v17, v0, v1, v2, #9
rgb_to_yuv_product v19, v20, v21, v25, v26, v18, v3, v4, v5, #9
rgb_to_yuv_product v22, v23, v24, v27, v28, v19, v3, v4, v5, #9
sub w5, w5, #16
add x3, x3, #(16*\element)
cmp w5, #16
stp q16, q17, [x0], #32 // store to dst_u
stp q18, q19, [x1], #32 // store to dst_v
b.ge 1b
cbz w5, 3f
2:
.if \alpha_first
ldrb w16, [x3, #1] // w16: r
ldrb w17, [x3, #2] // w17: g
ldrb w4, [x3, #3] // w4: b
.else
ldrb w16, [x3] // w16: r
ldrb w17, [x3, #1] // w17: g
ldrb w4, [x3, #2] // w4: b
.endif
smaddl x8, w16, w10, x9 // x8 = ru * r + const_offset
smaddl x8, w17, w11, x8 // x8 += gu * g
smaddl x8, w4, w12, x8 // x8 += bu * b
asr w8, w8, #9 // x8 >>= 9
strh w8, [x0], #2 // store to dst_u
smaddl x8, w16, w13, x9 // x8 = rv * r + const_offset
smaddl x8, w17, w14, x8 // x8 += gv * g
smaddl x8, w4, w15, x8 // x8 += bv * b
asr w8, w8, #9 // x8 >>= 9
sub w5, w5, #1 // width--
add x3, x3, #\element
strh w8, [x1], #2 // store to dst_v
cbnz w5, 2b
3:
ret
endfunc
.endm
rgbToUV_neon bgr24, rgb24, element=3
rgbToUV_neon bgra32, rgba32, element=4
rgbToUV_neon abgr32, argb32, element=4, alpha_first=1
#if HAVE_DOTPROD
ENABLE_DOTPROD
function ff_bgra32ToY_neon_dotprod, export=1
cmp w4, #0 // check width > 0
ldp w12, w11, [x5] // w12: ry, w11: gy
ldr w10, [x5, #8] // w10: by
b.gt 4f
ret
endfunc
function ff_rgba32ToY_neon_dotprod, export=1
cmp w4, #0 // check width > 0
ldp w10, w11, [x5] // w10: ry, w11: gy
ldr w12, [x5, #8] // w12: by
b.le 3f
4:
mov w9, #256 // w9 = 1 << (RGB2YUV_SHIFT - 7)
movk w9, #8, lsl #16 // w9 += 32 << (RGB2YUV_SHIFT - 1)
dup v6.4s, w9 // w9: const_offset
cmp w4, #16
mov w7, w10
bfi w7, w11, 8, 8 // the bfi instructions are used to assemble
bfi w7, w12, 16, 8 // 4 byte r,g,b,0 mask to be then used by udot.
dup v0.4s, w7 // v0 holds the lower byte of each coefficient
lsr w6, w10, #8
lsr w7, w11, #8
lsr w8, w12, #8
bfi w6, w7, 8, 8
bfi w6, w8, 16, 8
dup v1.4s, w6 // v1 holds the upper byte of each coefficient
b.lt 2f
1:
ld1 { v16.16b, v17.16b, v18.16b, v19.16b }, [x1], #64
sub w4, w4, #16 // width -= 16
mov v2.16b, v6.16b
mov v3.16b, v6.16b
mov v4.16b, v6.16b
mov v5.16b, v6.16b
cmp w4, #16 // width >= 16 ?
udot v2.4s, v16.16b, v0.16b
udot v3.4s, v17.16b, v0.16b
udot v4.4s, v18.16b, v0.16b
udot v5.4s, v19.16b, v0.16b
ushr v2.4s, v2.4s, #8
ushr v3.4s, v3.4s, #8
ushr v4.4s, v4.4s, #8
ushr v5.4s, v5.4s, #8
udot v2.4s, v16.16b, v1.16b
udot v3.4s, v17.16b, v1.16b
udot v4.4s, v18.16b, v1.16b
udot v5.4s, v19.16b, v1.16b
sqshrn v16.4h, v2.4s, #1
sqshrn2 v16.8h, v3.4s, #1
sqshrn v17.4h, v4.4s, #1
sqshrn2 v17.8h, v5.4s, #1
stp q16, q17, [x0], #32 // store to dst
b.ge 1b
cbz x4, 3f
2:
ldrb w13, [x1] // w13: r
ldrb w14, [x1, #1] // w14: g
ldrb w15, [x1, #2] // w15: b
smaddl x13, w13, w10, x9 // x13 = ry * r + const_offset
smaddl x13, w14, w11, x13 // x13 += gy * g
smaddl x13, w15, w12, x13 // x13 += by * b
asr w13, w13, #9 // x13 >>= 9
sub w4, w4, #1 // width--
add x1, x1, #4
strh w13, [x0], #2 // store to dst
cbnz w4, 2b
3:
ret
endfunc
DISABLE_DOTPROD
#endif
+228
View File
@@ -0,0 +1,228 @@
/*
* Copyright (c) 2016 Clément Bœsch <clement stupeflix.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/aarch64/asm.S"
function ff_yuv2planeX_8_neon, export=1
// x0 - const int16_t *filter,
// x1 - int filterSize,
// x2 - const int16_t **src,
// x3 - uint8_t *dest,
// w4 - int dstW,
// x5 - const uint8_t *dither,
// w6 - int offset
ld1 {v0.8b}, [x5] // load 8x8-bit dither
and w6, w6, #7
cbz w6, 1f // check if offsetting present
ext v0.8b, v0.8b, v0.8b, #3 // honor offsetting which can be 0 or 3 only
1: uxtl v0.8h, v0.8b // extend dither to 16-bit
ushll v1.4s, v0.4h, #12 // extend dither to 32-bit with left shift by 12 (part 1)
ushll2 v2.4s, v0.8h, #12 // extend dither to 32-bit with left shift by 12 (part 2)
cmp w1, #8 // if filterSize == 8, branch to specialized version
b.eq 6f
cmp w1, #4 // if filterSize == 4, branch to specialized version
b.eq 8f
cmp w1, #2 // if filterSize == 2, branch to specialized version
b.eq 10f
// The filter size does not match of the of specialized implementations. It is either even or odd. If it is even
// then use the first section below.
mov x7, #0 // i = 0
tbnz w1, #0, 4f // if filterSize % 2 != 0 branch to specialized version
// fs % 2 == 0
2: mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
mov w8, w1 // tmpfilterSize = filterSize
mov x9, x2 // srcp = src
mov x10, x0 // filterp = filter
3: ldp x11, x12, [x9], #16 // get 2 pointers: src[j] and src[j+1]
ldr s7, [x10], #4 // read 2x16-bit coeff X and Y at filter[j] and filter[j+1]
add x11, x11, x7, lsl #1 // &src[j ][i]
add x12, x12, x7, lsl #1 // &src[j+1][i]
ld1 {v5.8h}, [x11] // read 8x16-bit @ src[j ][i + {0..7}]: A,B,C,D,E,F,G,H
ld1 {v6.8h}, [x12] // read 8x16-bit @ src[j+1][i + {0..7}]: I,J,K,L,M,N,O,P
smlal v3.4s, v5.4h, v7.h[0] // val0 += {A,B,C,D} * X
smlal2 v4.4s, v5.8h, v7.h[0] // val1 += {E,F,G,H} * X
smlal v3.4s, v6.4h, v7.h[1] // val0 += {I,J,K,L} * Y
smlal2 v4.4s, v6.8h, v7.h[1] // val1 += {M,N,O,P} * Y
subs w8, w8, #2 // tmpfilterSize -= 2
b.gt 3b // loop until filterSize consumed
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
st1 {v3.8b}, [x3], #8 // write to destination
subs w4, w4, #8 // dstW -= 8
add x7, x7, #8 // i += 8
b.gt 2b // loop until width consumed
ret
// If filter size is odd (most likely == 1), then use this section.
// fs % 2 != 0
4: mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
mov w8, w1 // tmpfilterSize = filterSize
mov x9, x2 // srcp = src
mov x10, x0 // filterp = filter
5: ldr x11, [x9], #8 // get 1 pointer: src[j]
ldr h6, [x10], #2 // read 1 16 bit coeff X at filter[j]
add x11, x11, x7, lsl #1 // &src[j ][i]
ld1 {v5.8h}, [x11] // read 8x16-bit @ src[j ][i + {0..7}]: A,B,C,D,E,F,G,H
smlal v3.4s, v5.4h, v6.h[0] // val0 += {A,B,C,D} * X
smlal2 v4.4s, v5.8h, v6.h[0] // val1 += {E,F,G,H} * X
subs w8, w8, #1 // tmpfilterSize -= 2
b.gt 5b // loop until filterSize consumed
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
st1 {v3.8b}, [x3], #8 // write to destination
subs w4, w4, #8 // dstW -= 8
add x7, x7, #8 // i += 8
b.gt 4b // loop until width consumed
ret
6: // fs=8
ldp x5, x6, [x2] // load 2 pointers: src[j ] and src[j+1]
ldp x7, x9, [x2, #16] // load 2 pointers: src[j+2] and src[j+3]
ldp x10, x11, [x2, #32] // load 2 pointers: src[j+4] and src[j+5]
ldp x12, x13, [x2, #48] // load 2 pointers: src[j+6] and src[j+7]
// load 8x16-bit values for filter[j], where j=0..7
ld1 {v6.8h}, [x0]
7:
mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
ld1 {v24.8h}, [x5], #16 // load 8x16-bit values for src[j + 0][i + {0..7}]
ld1 {v25.8h}, [x6], #16 // load 8x16-bit values for src[j + 1][i + {0..7}]
ld1 {v26.8h}, [x7], #16 // load 8x16-bit values for src[j + 2][i + {0..7}]
ld1 {v27.8h}, [x9], #16 // load 8x16-bit values for src[j + 3][i + {0..7}]
ld1 {v28.8h}, [x10], #16 // load 8x16-bit values for src[j + 4][i + {0..7}]
ld1 {v29.8h}, [x11], #16 // load 8x16-bit values for src[j + 5][i + {0..7}]
ld1 {v30.8h}, [x12], #16 // load 8x16-bit values for src[j + 6][i + {0..7}]
ld1 {v31.8h}, [x13], #16 // load 8x16-bit values for src[j + 7][i + {0..7}]
smlal v3.4s, v24.4h, v6.h[0] // val0 += src[0][i + {0..3}] * filter[0]
smlal2 v4.4s, v24.8h, v6.h[0] // val1 += src[0][i + {4..7}] * filter[0]
smlal v3.4s, v25.4h, v6.h[1] // val0 += src[1][i + {0..3}] * filter[1]
smlal2 v4.4s, v25.8h, v6.h[1] // val1 += src[1][i + {4..7}] * filter[1]
smlal v3.4s, v26.4h, v6.h[2] // val0 += src[2][i + {0..3}] * filter[2]
smlal2 v4.4s, v26.8h, v6.h[2] // val1 += src[2][i + {4..7}] * filter[2]
smlal v3.4s, v27.4h, v6.h[3] // val0 += src[3][i + {0..3}] * filter[3]
smlal2 v4.4s, v27.8h, v6.h[3] // val1 += src[3][i + {4..7}] * filter[3]
smlal v3.4s, v28.4h, v6.h[4] // val0 += src[4][i + {0..3}] * filter[4]
smlal2 v4.4s, v28.8h, v6.h[4] // val1 += src[4][i + {4..7}] * filter[4]
smlal v3.4s, v29.4h, v6.h[5] // val0 += src[5][i + {0..3}] * filter[5]
smlal2 v4.4s, v29.8h, v6.h[5] // val1 += src[5][i + {4..7}] * filter[5]
smlal v3.4s, v30.4h, v6.h[6] // val0 += src[6][i + {0..3}] * filter[6]
smlal2 v4.4s, v30.8h, v6.h[6] // val1 += src[6][i + {4..7}] * filter[6]
smlal v3.4s, v31.4h, v6.h[7] // val0 += src[7][i + {0..3}] * filter[7]
smlal2 v4.4s, v31.8h, v6.h[7] // val1 += src[7][i + {4..7}] * filter[7]
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
subs w4, w4, #8 // dstW -= 8
st1 {v3.8b}, [x3], #8 // write to destination
b.gt 7b // loop until width consumed
ret
8: // fs=4
ldp x5, x6, [x2] // load 2 pointers: src[j ] and src[j+1]
ldp x7, x9, [x2, #16] // load 2 pointers: src[j+2] and src[j+3]
// load 4x16-bit values for filter[j], where j=0..3 and replicated across lanes
ld1 {v6.4h}, [x0]
9:
mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
ld1 {v24.8h}, [x5], #16 // load 8x16-bit values for src[j + 0][i + {0..7}]
ld1 {v25.8h}, [x6], #16 // load 8x16-bit values for src[j + 1][i + {0..7}]
ld1 {v26.8h}, [x7], #16 // load 8x16-bit values for src[j + 2][i + {0..7}]
ld1 {v27.8h}, [x9], #16 // load 8x16-bit values for src[j + 3][i + {0..7}]
smlal v3.4s, v24.4h, v6.h[0] // val0 += src[0][i + {0..3}] * filter[0]
smlal2 v4.4s, v24.8h, v6.h[0] // val1 += src[0][i + {4..7}] * filter[0]
smlal v3.4s, v25.4h, v6.h[1] // val0 += src[1][i + {0..3}] * filter[1]
smlal2 v4.4s, v25.8h, v6.h[1] // val1 += src[1][i + {4..7}] * filter[1]
smlal v3.4s, v26.4h, v6.h[2] // val0 += src[2][i + {0..3}] * filter[2]
smlal2 v4.4s, v26.8h, v6.h[2] // val1 += src[2][i + {4..7}] * filter[2]
smlal v3.4s, v27.4h, v6.h[3] // val0 += src[3][i + {0..3}] * filter[3]
smlal2 v4.4s, v27.8h, v6.h[3] // val1 += src[3][i + {4..7}] * filter[3]
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
st1 {v3.8b}, [x3], #8 // write to destination
subs w4, w4, #8 // dstW -= 8
b.gt 9b // loop until width consumed
ret
10: // fs=2
ldp x5, x6, [x2] // load 2 pointers: src[j ] and src[j+1]
// load 2x16-bit values for filter[j], where j=0..1 and replicated across lanes
ldr s6, [x0]
11:
mov v3.16b, v1.16b // initialize accumulator part 1 with dithering value
mov v4.16b, v2.16b // initialize accumulator part 2 with dithering value
ld1 {v24.8h}, [x5], #16 // load 8x16-bit values for src[j + 0][i + {0..7}]
ld1 {v25.8h}, [x6], #16 // load 8x16-bit values for src[j + 1][i + {0..7}]
smlal v3.4s, v24.4h, v6.h[0] // val0 += src[0][i + {0..3}] * filter[0]
smlal2 v4.4s, v24.8h, v6.h[0] // val1 += src[0][i + {4..7}] * filter[0]
smlal v3.4s, v25.4h, v6.h[1] // val0 += src[1][i + {0..3}] * filter[1]
smlal2 v4.4s, v25.8h, v6.h[1] // val1 += src[1][i + {4..7}] * filter[1]
sqshrun v3.4h, v3.4s, #16 // clip16(val0>>16)
sqshrun2 v3.8h, v4.4s, #16 // clip16(val1>>16)
uqshrn v3.8b, v3.8h, #3 // clip8(val>>19)
st1 {v3.8b}, [x3], #8 // write to destination
subs w4, w4, #8 // dstW -= 8
b.gt 11b // loop until width consumed
ret
endfunc
function ff_yuv2plane1_8_neon, export=1
// x0 - const int16_t *src,
// x1 - uint8_t *dest,
// w2 - int dstW,
// x3 - const uint8_t *dither,
// w4 - int offset
ld1 {v0.8b}, [x3] // load 8x8-bit dither
and w4, w4, #7
cbz w4, 1f // check if offsetting present
ext v0.8b, v0.8b, v0.8b, #3 // honor offsetting which can be 0 or 3 only
1:
uxtl v0.8h, v0.8b // extend dither to 32-bit
2:
ld1 {v3.8h}, [x0], #16 // read 8x16-bit @ src[j ][i + {0..7}]: A,B,C,D,E,F,G,H
subs w2, w2, #8 // dstW -= 8
shadd v1.8h, v0.8h, v3.8h // v1 = (v0 + v3) >> 1
sqshrun v2.8b, v1.8h, #6 // clip_uint8(v1 >> 6)
st1 {v2.8b}, [x1], #8 // write to destination
b.gt 2b // loop until width consumed
ret
endfunc
@@ -0,0 +1,181 @@
/*
* 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/aarch64/asm.S"
.macro lumConvertRange fromto, bit_depth
function ff_lumRange\fromto\()Jpeg\bit_depth\()_neon, export=1
// x0 int16_t *dst
// w1 int width
// w2 uint32_t coeff
// x3 int64_t offset
.if \bit_depth == 16
.ifc \fromto, To
movi v25.4s, #1
movi v24.4s, #1<<3, lsl #16
sub v24.4s, v24.4s, v25.4s
.endif
dup v25.4s, w2
dup v26.2d, x3
1:
ld1 {v0.4s, v1.4s}, [x0]
mov v16.16b, v26.16b
mov v17.16b, v26.16b
mov v18.16b, v26.16b
mov v19.16b, v26.16b
smlal v16.2d, v0.2s, v25.2s
smlal2 v17.2d, v0.4s, v25.4s
smlal v18.2d, v1.2s, v25.2s
smlal2 v19.2d, v1.4s, v25.4s
shrn v0.2s, v16.2d, 18
shrn2 v0.4s, v17.2d, 18
shrn v1.2s, v18.2d, 18
shrn2 v1.4s, v19.2d, 18
subs w1, w1, #8
.ifc \fromto, To
smin v0.4s, v0.4s, v24.4s
smin v1.4s, v1.4s, v24.4s
.endif
st1 {v0.4s, v1.4s}, [x0], #32
b.gt 1b
.else
dup v25.4s, w2
dup v26.4s, w3
1:
ld1 {v0.8h}, [x0]
mov v16.16b, v26.16b
mov v18.16b, v26.16b
sxtl v20.4s, v0.4h
sxtl2 v22.4s, v0.8h
mla v16.4s, v20.4s, v25.4s
mla v18.4s, v22.4s, v25.4s
.ifc \fromto, To
sqshrn v0.4h, v16.4s, 14
sqshrn2 v0.8h, v18.4s, 14
.else
shrn v0.4h, v16.4s, 14
shrn2 v0.8h, v18.4s, 14
.endif
subs w1, w1, #8
st1 {v0.8h}, [x0], #16
b.gt 1b
.endif
ret
endfunc
.endm
.macro chrConvertRange fromto, bit_depth
function ff_chrRange\fromto\()Jpeg\bit_depth\()_neon, export=1
// x0 int16_t *dstU
// x1 int16_t *dstV
// w2 int width
// w3 uint32_t coeff
// x4 int64_t offset
.if \bit_depth == 16
.ifc \fromto, To
movi v25.4s, #1
movi v24.4s, #1<<3, lsl #16
sub v24.4s, v24.4s, v25.4s
.endif
dup v25.4s, w3
dup v26.2d, x4
1:
ld1 {v0.4s, v1.4s}, [x0]
ld1 {v2.4s, v3.4s}, [x1]
mov v16.16b, v26.16b
mov v17.16b, v26.16b
mov v18.16b, v26.16b
mov v19.16b, v26.16b
mov v20.16b, v26.16b
mov v21.16b, v26.16b
mov v22.16b, v26.16b
mov v23.16b, v26.16b
smlal v16.2d, v0.2s, v25.2s
smlal2 v17.2d, v0.4s, v25.4s
smlal v18.2d, v1.2s, v25.2s
smlal2 v19.2d, v1.4s, v25.4s
smlal v20.2d, v2.2s, v25.2s
smlal2 v21.2d, v2.4s, v25.4s
smlal v22.2d, v3.2s, v25.2s
smlal2 v23.2d, v3.4s, v25.4s
shrn v0.2s, v16.2d, 18
shrn2 v0.4s, v17.2d, 18
shrn v1.2s, v18.2d, 18
shrn2 v1.4s, v19.2d, 18
shrn v2.2s, v20.2d, 18
shrn2 v2.4s, v21.2d, 18
shrn v3.2s, v22.2d, 18
shrn2 v3.4s, v23.2d, 18
subs w2, w2, #8
.ifc \fromto, To
smin v0.4s, v0.4s, v24.4s
smin v1.4s, v1.4s, v24.4s
smin v2.4s, v2.4s, v24.4s
smin v3.4s, v3.4s, v24.4s
.endif
st1 {v0.4s, v1.4s}, [x0], #32
st1 {v2.4s, v3.4s}, [x1], #32
b.gt 1b
.else
dup v25.4s, w3
dup v26.4s, w4
1:
ld1 {v0.8h}, [x0]
ld1 {v1.8h}, [x1]
mov v16.16b, v26.16b
mov v17.16b, v26.16b
mov v18.16b, v26.16b
mov v19.16b, v26.16b
sxtl v20.4s, v0.4h
sxtl v21.4s, v1.4h
sxtl2 v22.4s, v0.8h
sxtl2 v23.4s, v1.8h
mla v16.4s, v20.4s, v25.4s
mla v17.4s, v21.4s, v25.4s
mla v18.4s, v22.4s, v25.4s
mla v19.4s, v23.4s, v25.4s
.ifc \fromto, To
sqshrn v0.4h, v16.4s, 14
sqshrn v1.4h, v17.4s, 14
sqshrn2 v0.8h, v18.4s, 14
sqshrn2 v1.8h, v19.4s, 14
.else
shrn v0.4h, v16.4s, 14
shrn v1.4h, v17.4s, 14
shrn2 v0.8h, v18.4s, 14
shrn2 v1.8h, v19.4s, 14
.endif
subs w2, w2, #8
st1 {v0.8h}, [x0], #16
st1 {v1.8h}, [x1], #16
b.gt 1b
.endif
ret
endfunc
.endm
lumConvertRange To, 8
lumConvertRange To, 16
chrConvertRange To, 8
chrConvertRange To, 16
lumConvertRange From, 8
lumConvertRange From, 16
chrConvertRange From, 8
chrConvertRange From, 16
+104
View File
@@ -0,0 +1,104 @@
/*
* 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 <stdint.h>
#include "config.h"
#include "libavutil/attributes.h"
#include "libavutil/aarch64/cpu.h"
#include "libavutil/cpu.h"
#include "libavutil/bswap.h"
#include "libswscale/rgb2rgb.h"
#include "libswscale/swscale.h"
#include "libswscale/swscale_internal.h"
// Only handle width aligned to 16
void ff_rgb24toyv12_neon(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
uint8_t *vdst, int width, int height, int lumStride,
int chromStride, int srcStride, const int32_t *rgb2yuv);
static void rgb24toyv12(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
uint8_t *vdst, int width, int height, int lumStride,
int chromStride, int srcStride, const int32_t *rgb2yuv)
{
int width_align = width & (~15);
if (width_align > 0)
ff_rgb24toyv12_neon(src, ydst, udst, vdst, width_align, height,
lumStride, chromStride, srcStride, rgb2yuv);
if (width_align < width) {
src += width_align * 3;
ydst += width_align;
udst += width_align / 2;
vdst += width_align / 2;
ff_rgb24toyv12_c(src, ydst, udst, vdst, width - width_align, height,
lumStride, chromStride, srcStride, rgb2yuv);
}
}
void ff_interleave_bytes_neon(const uint8_t *src1, const uint8_t *src2,
uint8_t *dest, int width, int height,
int src1Stride, int src2Stride, int dstStride);
void ff_deinterleave_bytes_neon(const uint8_t *src, uint8_t *dst1, uint8_t *dst2,
int width, int height, int srcStride,
int dst1Stride, int dst2Stride);
void ff_shuffle_bytes_0321_neon(const uint8_t *src, uint8_t *dst, int src_size);
void ff_shuffle_bytes_2103_neon(const uint8_t *src, uint8_t *dst, int src_size);
void ff_shuffle_bytes_1230_neon(const uint8_t *src, uint8_t *dst, int src_size);
void ff_shuffle_bytes_3012_neon(const uint8_t *src, uint8_t *dst, int src_size);
void ff_shuffle_bytes_3210_neon(const uint8_t *src, uint8_t *dst, int src_size);
void ff_shuffle_bytes_3102_neon(const uint8_t *src, uint8_t *dst, int src_size);
void ff_shuffle_bytes_2013_neon(const uint8_t *src, uint8_t *dst, int src_size);
void ff_shuffle_bytes_2130_neon(const uint8_t *src, uint8_t *dst, int src_size);
void ff_shuffle_bytes_1203_neon(const uint8_t *src, uint8_t *dst, int src_size);
void ff_uyvytoyuv422_neon(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
const uint8_t *src, int width, int height,
int lumStride, int chromStride, int srcStride);
void ff_uyvytoyuv420_neon(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
const uint8_t *src, int width, int height,
int lumStride, int chromStride, int srcStride);
void ff_yuyvtoyuv420_neon(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
const uint8_t *src, int width, int height,
int lumStride, int chromStride, int srcStride);
void ff_yuyvtoyuv422_neon(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
const uint8_t *src, int width, int height,
int lumStride, int chromStride, int srcStride);
av_cold void rgb2rgb_init_aarch64(void)
{
int cpu_flags = av_get_cpu_flags();
if (have_neon(cpu_flags)) {
ff_rgb24toyv12 = rgb24toyv12;
interleaveBytes = ff_interleave_bytes_neon;
deinterleaveBytes = ff_deinterleave_bytes_neon;
shuffle_bytes_0321 = ff_shuffle_bytes_0321_neon;
shuffle_bytes_1230 = ff_shuffle_bytes_1230_neon;
shuffle_bytes_2103 = ff_shuffle_bytes_2103_neon;
shuffle_bytes_3012 = ff_shuffle_bytes_3012_neon;
shuffle_bytes_3210 = ff_shuffle_bytes_3210_neon;
shuffle_bytes_3102 = ff_shuffle_bytes_3102_neon;
shuffle_bytes_2013 = ff_shuffle_bytes_2013_neon;
shuffle_bytes_2130 = ff_shuffle_bytes_2130_neon;
shuffle_bytes_1203 = ff_shuffle_bytes_1203_neon;
uyvytoyuv422 = ff_uyvytoyuv422_neon;
uyvytoyuv420 = ff_uyvytoyuv420_neon;
yuyvtoyuv422 = ff_yuyvtoyuv422_neon;
yuyvtoyuv420 = ff_yuyvtoyuv420_neon;
}
}
+689
View File
@@ -0,0 +1,689 @@
/*
* Copyright (c) 2020 Martin Storsjo
* 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/aarch64/asm.S"
#define RGB2YUV_COEFFS 16*4+16*32
#define BY v0.h[0]
#define GY v0.h[1]
#define RY v0.h[2]
#define BU v1.h[0]
#define GU v1.h[1]
#define RU v1.h[2]
#define BV v2.h[0]
#define GV v2.h[1]
#define RV v2.h[2]
#define Y_OFFSET v22
#define UV_OFFSET v23
const shuf_0321_tbl, align=4
.byte 0, 3, 2, 1
.byte 4, 7, 6, 5
.byte 8, 11, 10, 9
.byte 12, 15, 14, 13
endconst
const shuf_1230_tbl, align=4
.byte 1, 2, 3, 0
.byte 5, 6, 7, 4
.byte 9, 10, 11, 8
.byte 13, 14, 15, 12
endconst
const shuf_2103_tbl, align=4
.byte 2, 1, 0, 3
.byte 6, 5, 4, 7
.byte 10, 9, 8, 11
.byte 14, 13, 12, 15
endconst
const shuf_3012_tbl, align=4
.byte 3, 0, 1, 2
.byte 7, 4, 5, 6
.byte 11, 8, 9, 10
.byte 15, 12, 13, 14
endconst
const shuf_3210_tbl, align=4
.byte 3, 2, 1, 0
.byte 7, 6, 5, 4
.byte 11, 10, 9, 8
.byte 15, 14, 13, 12
endconst
const shuf_3102_tbl, align=4
.byte 3, 1, 0, 2
.byte 7, 5, 4, 6
.byte 11, 9, 8, 10
.byte 15, 13, 12, 14
endconst
const shuf_2013_tbl, align=4
.byte 2, 0, 1, 3
.byte 6, 4, 5, 7
.byte 10, 8, 9, 11
.byte 14, 12, 13, 15
endconst
const shuf_1203_tbl, align=4
.byte 1, 2, 0, 3
.byte 5, 6, 4, 7
.byte 9, 10, 8, 11
.byte 13, 14, 12, 15
endconst
const shuf_2130_tbl, align=4
.byte 2, 1, 3, 0
.byte 6, 5, 7, 4
.byte 10, 9, 11, 8
.byte 14, 13, 15, 12
endconst
// convert rgb to 16-bit y, u, or v
// uses v3 and v4
.macro rgbconv16 dst, b, g, r, bc, gc, rc, shr_bits
smull v3.4s, \b\().4h, \bc
smlal v3.4s, \g\().4h, \gc
smlal v3.4s, \r\().4h, \rc
smull2 v4.4s, \b\().8h, \bc
smlal2 v4.4s, \g\().8h, \gc
smlal2 v4.4s, \r\().8h, \rc // v3:v4 = b * bc + g * gc + r * rc (32-bit)
shrn \dst\().4h, v3.4s, \shr_bits
shrn2 \dst\().8h, v4.4s, \shr_bits // dst = b * bc + g * gc + r * rc (16-bit)
.endm
// void ff_rgb24toyv12_neon(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
// uint8_t *vdst, int width, int height, int lumStride,
// int chromStride, int srcStride, int32_t *rgb2yuv);
function ff_rgb24toyv12_neon, export=1
// x0 const uint8_t *src
// x1 uint8_t *ydst
// x2 uint8_t *udst
// x3 uint8_t *vdst
// w4 int width
// w5 int height
// w6 int lumStride
// w7 int chromStride
ldrsw x14, [sp]
ldr x15, [sp, #8]
// x14 int srcStride
// x15 int32_t *rgb2yuv
// extend width and stride parameters
uxtw x4, w4
sxtw x6, w6
sxtw x7, w7
// src1 = x0
// src2 = x10
add x10, x0, x14 // x10 = src + srcStride
lsl x14, x14, #1 // srcStride *= 2
add x11, x4, x4, lsl #1 // x11 = 3 * width
sub x14, x14, x11 // srcPadding = (2 * srcStride) - (3 * width)
// ydst1 = x1
// ydst2 = x11
add x11, x1, x6 // x11 = ydst + lumStride
lsl x6, x6, #1 // lumStride *= 2
sub x6, x6, x4 // lumPadding = (2 * lumStride) - width
sub x7, x7, x4, lsr #1 // chromPadding = chromStride - (width / 2)
// load rgb2yuv coefficients into v0, v1, and v2
add x15, x15, #RGB2YUV_COEFFS
ld1 {v0.8h-v2.8h}, [x15] // load 24 values
// load offset constants
movi Y_OFFSET.8h, #0x10, lsl #8
movi UV_OFFSET.8h, #0x80, lsl #8
1:
mov w15, w4 // w15 = width
2:
// load first line
ld3 {v26.16b, v27.16b, v28.16b}, [x0], #48
// widen first line to 16-bit
uxtl v16.8h, v26.8b // v16 = B11
uxtl v17.8h, v27.8b // v17 = G11
uxtl v18.8h, v28.8b // v18 = R11
uxtl2 v19.8h, v26.16b // v19 = B12
uxtl2 v20.8h, v27.16b // v20 = G12
uxtl2 v21.8h, v28.16b // v21 = R12
// calculate Y values for first line
rgbconv16 v24, v16, v17, v18, BY, GY, RY, #7 // v24 = Y11
rgbconv16 v25, v19, v20, v21, BY, GY, RY, #7 // v25 = Y12
// load second line
ld3 {v26.16b, v27.16b, v28.16b}, [x10], #48
// pairwise add and save rgb values to calculate average
addp v5.8h, v16.8h, v19.8h
addp v6.8h, v17.8h, v20.8h
addp v7.8h, v18.8h, v21.8h
// widen second line to 16-bit
uxtl v16.8h, v26.8b // v16 = B21
uxtl v17.8h, v27.8b // v17 = G21
uxtl v18.8h, v28.8b // v18 = R21
uxtl2 v19.8h, v26.16b // v19 = B22
uxtl2 v20.8h, v27.16b // v20 = G22
uxtl2 v21.8h, v28.16b // v21 = R22
// calculate Y values for second line
rgbconv16 v26, v16, v17, v18, BY, GY, RY, #7 // v26 = Y21
rgbconv16 v27, v19, v20, v21, BY, GY, RY, #7 // v27 = Y22
// pairwise add rgb values to calculate average
addp v16.8h, v16.8h, v19.8h
addp v17.8h, v17.8h, v20.8h
addp v18.8h, v18.8h, v21.8h
// calculate sum of r, g, b components in 2x2 blocks
add v16.8h, v16.8h, v5.8h
add v17.8h, v17.8h, v6.8h
add v18.8h, v18.8h, v7.8h
// calculate U and V values
rgbconv16 v28, v16, v17, v18, BU, GU, RU, #9 // v28 = U
rgbconv16 v29, v16, v17, v18, BV, GV, RV, #9 // v29 = V
// add offsets and narrow all values
addhn v24.8b, v24.8h, Y_OFFSET.8h
addhn v25.8b, v25.8h, Y_OFFSET.8h
addhn v26.8b, v26.8h, Y_OFFSET.8h
addhn v27.8b, v27.8h, Y_OFFSET.8h
addhn v28.8b, v28.8h, UV_OFFSET.8h
addhn v29.8b, v29.8h, UV_OFFSET.8h
subs w15, w15, #16
// store output
st1 {v24.8b, v25.8b}, [x1], #16 // store ydst1
st1 {v26.8b, v27.8b}, [x11], #16 // store ydst2
st1 {v28.8b}, [x2], #8 // store udst
st1 {v29.8b}, [x3], #8 // store vdst
b.gt 2b
subs w5, w5, #2
// row += 2
add x0, x0, x14 // src1 += srcPadding
add x10, x10, x14 // src2 += srcPadding
add x1, x1, x6 // ydst1 += lumPadding
add x11, x11, x6 // ydst2 += lumPadding
add x2, x2, x7 // udst += chromPadding
add x3, x3, x7 // vdst += chromPadding
b.gt 1b
ret
endfunc
// void ff_interleave_bytes_neon(const uint8_t *src1, const uint8_t *src2,
// uint8_t *dest, int width, int height,
// int src1Stride, int src2Stride, int dstStride);
function ff_interleave_bytes_neon, export=1
sub w5, w5, w3
sub w6, w6, w3
sub w7, w7, w3, lsl #1
1:
ands w8, w3, #0xfffffff0 // & ~15
b.eq 3f
2:
ld1 {v0.16b}, [x0], #16
ld1 {v1.16b}, [x1], #16
subs w8, w8, #16
st2 {v0.16b, v1.16b}, [x2], #32
b.gt 2b
tst w3, #15
b.eq 9f
3:
tst w3, #8
b.eq 4f
ld1 {v0.8b}, [x0], #8
ld1 {v1.8b}, [x1], #8
st2 {v0.8b, v1.8b}, [x2], #16
4:
tst w3, #4
b.eq 5f
ld1 {v0.s}[0], [x0], #4
ld1 {v1.s}[0], [x1], #4
zip1 v0.8b, v0.8b, v1.8b
st1 {v0.8b}, [x2], #8
5:
ands w8, w3, #3
b.eq 9f
6:
ldrb w9, [x0], #1
ldrb w10, [x1], #1
subs w8, w8, #1
bfi w9, w10, #8, #8
strh w9, [x2], #2
b.gt 6b
9:
subs w4, w4, #1
b.eq 0f
add x0, x0, w5, sxtw
add x1, x1, w6, sxtw
add x2, x2, w7, sxtw
b 1b
0:
ret
endfunc
// void ff_deinterleave_bytes_neon(const uint8_t *src, uint8_t *dst1, uint8_t *dst2,
// int width, int height, int srcStride,
// int dst1Stride, int dst2Stride);
function ff_deinterleave_bytes_neon, export=1
sub w5, w5, w3, lsl #1
sub w6, w6, w3
sub w7, w7, w3
1:
ands w8, w3, #0xfffffff0 // & ~15
b.eq 3f
2:
ld2 {v0.16b, v1.16b}, [x0], #32
subs w8, w8, #16
st1 {v0.16b}, [x1], #16
st1 {v1.16b}, [x2], #16
b.gt 2b
tst w3, #15
b.eq 9f
3:
tst w3, #8
b.eq 4f
ld2 {v0.8b, v1.8b}, [x0], #16
st1 {v0.8b}, [x1], #8
st1 {v1.8b}, [x2], #8
4:
tst w3, #4
b.eq 5f
ld1 {v0.8b}, [x0], #8
shrn v1.8b, v0.8h, #8
xtn v0.8b, v0.8h
st1 {v0.s}[0], [x1], #4
st1 {v1.s}[0], [x2], #4
5:
ands w8, w3, #3
b.eq 9f
6:
ldrh w9, [x0], #2
subs w8, w8, #1
ubfx w10, w9, #8, #8
strb w9, [x1], #1
strb w10, [x2], #1
b.gt 6b
9:
subs w4, w4, #1
b.eq 0f
add x0, x0, w5, sxtw
add x1, x1, w6, sxtw
add x2, x2, w7, sxtw
b 1b
0:
ret
endfunc
.macro neon_shuf shuf
function ff_shuffle_bytes_\shuf\()_neon, export=1
movrel x9, shuf_\shuf\()_tbl
ld1 {v1.16b}, [x9]
and w5, w2, #~15
and w3, w2, #8
and w4, w2, #4
cbz w5, 2f
1:
ld1 {v0.16b}, [x0], #16
subs w5, w5, #16
tbl v0.16b, {v0.16b}, v1.16b
st1 {v0.16b}, [x1], #16
b.gt 1b
2:
cbz w3, 3f
ld1 {v0.8b}, [x0], #8
tbl v0.8b, {v0.16b}, v1.8b
st1 {v0.8b}, [x1], #8
3:
cbz w4, 4f
.if \shuf == 0321
ldr w5, [x0]
rev w5, w5
ror w5, w5, #24
str w5, [x1]
.endif
.if \shuf == 1230
ldr w5, [x0]
ror w5, w5, #8
str w5, [x1]
.endif
.if \shuf == 2103
ldr w5, [x0]
rev w5, w5
ror w5, w5, #8
str w5, [x1]
.endif
.if \shuf == 3012
ldr w5, [x0]
ror w5, w5, #24
str w5, [x1]
.endif
.if \shuf == 3210
ldr w5, [x0]
rev w5, w5
str w5, [x1]
.endif
.if \shuf == 3102 || \shuf == 2013 || \shuf == 1203 || \shuf == 2130
ld1 {v0.s}[0], [x0]
tbl v0.8b, {v0.16b}, v1.8b
st1 {v0.s}[0], [x1]
.endif
4:
ret
endfunc
.endm
neon_shuf 0321
neon_shuf 1230
neon_shuf 2103
neon_shuf 3012
neon_shuf 3102
neon_shuf 2013
neon_shuf 1203
neon_shuf 2130
neon_shuf 3210
/*
v0-v7 - two consecutive lines
x0 - upper Y destination
x1 - U destination
x2 - V destination
x3 - upper src line
w5 - width/iteration counter - count of line pairs for yuv420, of single lines for 422
x6 - lum padding
x7 - chrom padding
x8 - src padding
w9 - number of bytes remaining in the tail
x10 - lower Y destination
w12 - tmp
x13 - lower src line
w14 - tmp
w17 - set to 1 if last line has to be handled separately (odd height)
*/
// one fast path iteration processes 16 uyvy tuples
// is_line_tail is set to 1 when final 16 tuples are being processed
// skip_storing_chroma is set to 1 when final line is processed and the height is odd
.macro fastpath_iteration src_fmt, dst_fmt, is_line_tail, skip_storing_chroma
ld4 {v0.16b - v3.16b}, [x3], #64
.if ! \is_line_tail
subs w14, w14, #32
.endif
.if ! \skip_storing_chroma
.ifc \dst_fmt, yuv420
ld4 {v4.16b - v7.16b}, [x13], #64
.endif
.ifc \dst_fmt, yuv420 // store UV
.ifc \src_fmt, uyvy
uhadd v0.16b, v4.16b, v0.16b // halving sum of U
uhadd v2.16b, v6.16b, v2.16b // halving sum of V
.else
uhadd v1.16b, v5.16b, v1.16b // halving sum of U
uhadd v3.16b, v7.16b, v3.16b // halving sum of V
.endif
.endif
.ifc \src_fmt, uyvy
st1 {v2.16b}, [x2], #16
st1 {v0.16b}, [x1], #16
.else
st1 {v3.16b}, [x2], #16
st1 {v1.16b}, [x1], #16
.endif
.ifc \dst_fmt, yuv420 // store_y
.ifc \src_fmt, uyvy
mov v6.16b, v5.16b
st2 {v6.16b,v7.16b}, [x10], #32
.else
mov v5.16b, v4.16b
st2 {v5.16b,v6.16b}, [x10], #32
.endif
.endif
.endif // ! \skip_storing_chroma
.ifc \src_fmt, uyvy
mov v2.16b, v1.16b
st2 {v2.16b,v3.16b}, [x0], #32
.else
mov v1.16b, v0.16b
st2 {v1.16b,v2.16b}, [x0], #32
.endif
.endm
// shift pointers back to width - 32 to process the tail of the line
// if the height is odd, processing the final line is simplified
.macro fastpath_shift_back_pointers src_fmt, dst_fmt, is_final_odd_line
add x3, x3, w9, sxtw #1
sub x3, x3, #64
.if ! \is_final_odd_line
.ifc \dst_fmt, yuv420
add x13, x13, w9, sxtw #1
sub x13, x13, #64
add x10, x10, w9, sxtw
sub x10, x10, #32
.endif
.endif
add x0, x0, w9, sxtw
sub x0, x0, #32
.if ! \is_final_odd_line
asr w14, w9, #1
add x1, x1, w14, sxtw
sub x1, x1, #16
add x2, x2, w14, sxtw
sub x2, x2, #16
.endif
.endm
.macro slowpath_iteration src_fmt, dst_fmt, skip_storing_chroma
.ifc \dst_fmt, yuv422
.ifc \src_fmt, uyvy
ldrb w12, [x3], #1
ldrb w14, [x3], #1
strb w12, [x1], #1
strb w14, [x0], #1
ldrb w12, [x3], #1
ldrb w14, [x3], #1
strb w12, [x2], #1
strb w14, [x0], #1
.else
ldrb w12, [x3], #1
ldrb w14, [x3], #1
strb w12, [x0], #1
strb w14, [x1], #1
ldrb w12, [x3], #1
ldrb w14, [x3], #1
strb w12, [x0], #1
strb w14, [x2], #1
.endif
.endif
.ifc \dst_fmt, yuv420
.ifc \src_fmt, uyvy
.if \skip_storing_chroma
ldrb w12, [x3], #2
ldrb w14, [x3], #2
strb w12, [x0], #1
strb w14, [x0], #1
.else
ldrb w12, [x3], #1
ldrb w14, [x13], #1
add w12, w12, w14
lsr w12, w12, #1
strb w12, [x1], #1
ldrb w14, [x3], #1
ldrb w12, [x13], #1
strb w14, [x0], #1
strb w12, [x10], #1
ldrb w14, [x13], #1
ldrb w12, [x3], #1
add w12, w12, w14
lsr w12, w12, #1
strb w12, [x2], #1
ldrb w14, [x3], #1
ldrb w12, [x13], #1
strb w14, [x0], #1
strb w12, [x10], #1
.endif
.else
.if \skip_storing_chroma
ldrb w12, [x3], #2
ldrb w14, [x3], #2
strb w12, [x0], #1
strb w14, [x0], #1
.else
ldrb w12, [x3], #1
ldrb w14, [x13], #1
strb w12, [x0], #1
strb w14, [x10], #1
ldrb w12, [x3], #1
ldrb w14, [x13], #1
add w12, w12, w14
lsr w12, w12, #1
strb w12, [x1], #1
ldrb w14, [x3], #1
ldrb w12, [x13], #1
strb w14, [x0], #1
strb w12, [x10], #1
ldrb w14, [x13], #1
ldrb w12, [x3], #1
add w12, w12, w14
lsr w12, w12, #1
strb w12, [x2], #1
.endif
.endif
.endif
.endm
.macro move_pointers_to_next_line src_fmt, dst_fmt, is_final_odd_line
add x3, x3, x8
add x0, x0, x6
.ifc \dst_fmt, yuv420
add x13, x13, x8
add x10, x10, x6
.endif
add x1, x1, x7
add x2, x2, x7
.endm
.macro interleaved_yuv_to_planar src_fmt, dst_fmt
function ff_\src_fmt\()to\dst_fmt\()_neon, export=1
sxtw x6, w6
sxtw x7, w7
ldrsw x8, [sp]
ands w11, w4, #~31 // choose between fast and slow path
.ifc \dst_fmt, yuv420
add x10, x0, x6
add x13, x3, x8
add x8, x8, x8
add x6, x6, x6
and w17, w5, #1
asr w5, w5, #1
.endif
asr w9, w4, #1
sub x8, x8, w4, sxtw #1 // src offset
sub x6, x6, w4, sxtw // lum offset
sub x7, x7, x9 // chr offset
b.eq 6f
1: // fast path - the width is at least 32
and w14, w4, #~31 // w14 is the main loop counter
and w9, w4, #31 // w9 holds the remaining width, 0 to 31
2:
fastpath_iteration \src_fmt, \dst_fmt, 0, 0
b.ne 2b
fastpath_shift_back_pointers \src_fmt, \dst_fmt, 0
fastpath_iteration \src_fmt, \dst_fmt, 0, 0
subs w5, w5, #1
move_pointers_to_next_line \src_fmt, \dst_fmt
b.ne 1b
.ifc \dst_fmt, yuv420 // handle the last line in case the height is odd
cbz w17, 3f
and w14, w4, #~31
4:
fastpath_iteration \src_fmt, \dst_fmt, 0, 1
b.ne 4b
fastpath_shift_back_pointers \src_fmt, \dst_fmt, 1
fastpath_iteration \src_fmt, \dst_fmt, 1, 1
3:
.endif
ret
6: // slow path - width is at most 31
and w9, w4, #31
7:
subs w9, w9, #2
slowpath_iteration \src_fmt, \dst_fmt, 0
b.ne 7b
subs w5, w5, #1
move_pointers_to_next_line \src_fmt, \dst_fmt
b.ne 6b
.ifc \dst_fmt, yuv420
cbz w17, 8f
and w9, w4, #31
.ifc \src_fmt, uyvy
add x3, x3, #1
.endif
5:
subs w9, w9, #2
slowpath_iteration \src_fmt, \dst_fmt, 1
b.ne 5b
8:
.endif
ret
endfunc
.endm
interleaved_yuv_to_planar uyvy, yuv422
interleaved_yuv_to_planar uyvy, yuv420
interleaved_yuv_to_planar yuyv, yuv422
interleaved_yuv_to_planar yuyv, yuv420
+337
View File
@@ -0,0 +1,337 @@
/*
* 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 "config.h"
#include "libavutil/attributes.h"
#include "libswscale/swscale.h"
#include "libswscale/swscale_internal.h"
#include "libavutil/aarch64/cpu.h"
void ff_hscale16to15_4_neon_asm(int shift, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize);
void ff_hscale16to15_X8_neon_asm(int shift, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize);
void ff_hscale16to15_X4_neon_asm(int shift, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize);
void ff_hscale16to19_4_neon_asm(int shift, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize);
void ff_hscale16to19_X8_neon_asm(int shift, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize);
void ff_hscale16to19_X4_neon_asm(int shift, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize);
static void ff_hscale16to15_4_neon(SwsInternal *c, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
int sh = desc->comp[0].depth - 1;
if (sh<15) {
sh = isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1);
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
sh = 16 - 1;
}
ff_hscale16to15_4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
}
static void ff_hscale16to15_X8_neon(SwsInternal *c, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
int sh = desc->comp[0].depth - 1;
if (sh<15) {
sh = isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1);
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
sh = 16 - 1;
}
ff_hscale16to15_X8_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
}
static void ff_hscale16to15_X4_neon(SwsInternal *c, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
int sh = desc->comp[0].depth - 1;
if (sh<15) {
sh = isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1);
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
sh = 16 - 1;
}
ff_hscale16to15_X4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
}
static void ff_hscale16to19_4_neon(SwsInternal *c, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
int bits = desc->comp[0].depth - 1;
int sh = bits - 4;
if ((isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) {
sh = 9;
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
sh = 16 - 1 - 4;
}
ff_hscale16to19_4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
}
static void ff_hscale16to19_X8_neon(SwsInternal *c, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
int bits = desc->comp[0].depth - 1;
int sh = bits - 4;
if ((isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) {
sh = 9;
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
sh = 16 - 1 - 4;
}
ff_hscale16to19_X8_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
}
static void ff_hscale16to19_X4_neon(SwsInternal *c, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format);
int bits = desc->comp[0].depth - 1;
int sh = bits - 4;
if ((isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) {
sh = 9;
} else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */
sh = 16 - 1 - 4;
}
ff_hscale16to19_X4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
}
#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, 8, 19, opt);
#define ALL_SCALE_FUNCS(opt) \
SCALE_FUNCS(4, opt); \
SCALE_FUNCS(X8, opt); \
SCALE_FUNCS(X4, opt)
ALL_SCALE_FUNCS(neon);
void ff_yuv2planeX_8_neon(const int16_t *filter, int filterSize,
const int16_t **src, uint8_t *dest, int dstW,
const uint8_t *dither, int offset);
void ff_yuv2plane1_8_neon(
const int16_t *src,
uint8_t *dest,
int dstW,
const uint8_t *dither,
int offset);
#define ASSIGN_SCALE_FUNC2(hscalefn, filtersize, opt) do { \
if (c->srcBpc == 8) { \
if(c->dstBpc <= 14) { \
hscalefn = \
ff_hscale8to15_ ## filtersize ## _ ## opt; \
} else \
hscalefn = \
ff_hscale8to19_ ## filtersize ## _ ## opt; \
} else { \
if (c->dstBpc <= 14) \
hscalefn = \
ff_hscale16to15_ ## filtersize ## _ ## opt; \
else \
hscalefn = \
ff_hscale16to19_ ## filtersize ## _ ## opt; \
} \
} while (0)
#define ASSIGN_SCALE_FUNC(hscalefn, filtersize, opt) do { \
if (filtersize == 4) \
ASSIGN_SCALE_FUNC2(hscalefn, 4, opt); \
else if (filtersize % 8 == 0) \
ASSIGN_SCALE_FUNC2(hscalefn, X8, opt); \
else if (filtersize % 4 == 0 && filtersize % 8 != 0) \
ASSIGN_SCALE_FUNC2(hscalefn, X4, opt); \
} while (0)
#define ASSIGN_VSCALE_FUNC(vscalefn, opt) \
switch (c->dstBpc) { \
case 8: vscalefn = ff_yuv2plane1_8_ ## opt; break; \
default: break; \
}
#define NEON_INPUT(name) \
void ff_##name##ToY_neon(uint8_t *dst, const uint8_t *src, const uint8_t *, \
const uint8_t *, int w, uint32_t *coeffs, void *); \
void ff_##name##ToUV_neon(uint8_t *, uint8_t *, const uint8_t *, \
const uint8_t *, const uint8_t *, int w, \
uint32_t *coeffs, void *); \
void ff_##name##ToUV_half_neon(uint8_t *, uint8_t *, const uint8_t *, \
const uint8_t *, const uint8_t *, int w, \
uint32_t *coeffs, void *)
#define NEON_INPUT_DOTPROD(name) \
void ff_##name##ToY_neon_dotprod(uint8_t *dst, const uint8_t *src, const uint8_t *, \
const uint8_t *, int w, uint32_t *coeffs, void *);
NEON_INPUT(abgr32);
NEON_INPUT(argb32);
NEON_INPUT(bgr24);
NEON_INPUT(bgra32);
NEON_INPUT(rgb24);
NEON_INPUT(rgba32);
NEON_INPUT_DOTPROD(bgra32);
NEON_INPUT_DOTPROD(rgba32);
void ff_lumRangeFromJpeg8_neon(int16_t *dst, int width,
uint32_t coeff, int64_t offset);
void ff_chrRangeFromJpeg8_neon(int16_t *dstU, int16_t *dstV, int width,
uint32_t coeff, int64_t offset);
void ff_lumRangeToJpeg8_neon(int16_t *dst, int width,
uint32_t coeff, int64_t offset);
void ff_chrRangeToJpeg8_neon(int16_t *dstU, int16_t *dstV, int width,
uint32_t coeff, int64_t offset);
void ff_lumRangeFromJpeg16_neon(int16_t *dst, int width,
uint32_t coeff, int64_t offset);
void ff_chrRangeFromJpeg16_neon(int16_t *dstU, int16_t *dstV, int width,
uint32_t coeff, int64_t offset);
void ff_lumRangeToJpeg16_neon(int16_t *dst, int width,
uint32_t coeff, int64_t offset);
void ff_chrRangeToJpeg16_neon(int16_t *dstU, int16_t *dstV, int width,
uint32_t coeff, int64_t offset);
av_cold void ff_sws_init_range_convert_aarch64(SwsInternal *c)
{
int cpu_flags = av_get_cpu_flags();
if (have_neon(cpu_flags)) {
if (c->dstBpc <= 14) {
if (c->opts.src_range) {
c->lumConvertRange = ff_lumRangeFromJpeg8_neon;
c->chrConvertRange = ff_chrRangeFromJpeg8_neon;
} else {
c->lumConvertRange = ff_lumRangeToJpeg8_neon;
c->chrConvertRange = ff_chrRangeToJpeg8_neon;
}
} else {
if (c->opts.src_range) {
c->lumConvertRange = ff_lumRangeFromJpeg16_neon;
c->chrConvertRange = ff_chrRangeFromJpeg16_neon;
} else {
c->lumConvertRange = ff_lumRangeToJpeg16_neon;
c->chrConvertRange = ff_chrRangeToJpeg16_neon;
}
}
}
}
av_cold void ff_sws_init_swscale_aarch64(SwsInternal *c)
{
int cpu_flags = av_get_cpu_flags();
if (have_neon(cpu_flags)) {
ASSIGN_SCALE_FUNC(c->hyScale, c->hLumFilterSize, neon);
ASSIGN_SCALE_FUNC(c->hcScale, c->hChrFilterSize, neon);
ASSIGN_VSCALE_FUNC(c->yuv2plane1, neon);
if (c->dstBpc == 8) {
c->yuv2planeX = ff_yuv2planeX_8_neon;
}
switch (c->opts.src_format) {
case AV_PIX_FMT_ABGR:
c->lumToYV12 = ff_abgr32ToY_neon;
if (c->chrSrcHSubSample)
c->chrToYV12 = ff_abgr32ToUV_half_neon;
else
c->chrToYV12 = ff_abgr32ToUV_neon;
break;
case AV_PIX_FMT_ARGB:
c->lumToYV12 = ff_argb32ToY_neon;
if (c->chrSrcHSubSample)
c->chrToYV12 = ff_argb32ToUV_half_neon;
else
c->chrToYV12 = ff_argb32ToUV_neon;
break;
case AV_PIX_FMT_BGR24:
c->lumToYV12 = ff_bgr24ToY_neon;
if (c->chrSrcHSubSample)
c->chrToYV12 = ff_bgr24ToUV_half_neon;
else
c->chrToYV12 = ff_bgr24ToUV_neon;
break;
case AV_PIX_FMT_BGRA:
c->lumToYV12 = ff_bgra32ToY_neon;
#if HAVE_DOTPROD
if (have_dotprod(cpu_flags)) {
c->lumToYV12 = ff_bgra32ToY_neon_dotprod;
}
#endif
if (c->chrSrcHSubSample)
c->chrToYV12 = ff_bgra32ToUV_half_neon;
else
c->chrToYV12 = ff_bgra32ToUV_neon;
break;
case AV_PIX_FMT_RGB24:
c->lumToYV12 = ff_rgb24ToY_neon;
if (c->chrSrcHSubSample)
c->chrToYV12 = ff_rgb24ToUV_half_neon;
else
c->chrToYV12 = ff_rgb24ToUV_neon;
break;
case AV_PIX_FMT_RGBA:
c->lumToYV12 = ff_rgba32ToY_neon;
#if HAVE_DOTPROD
if (have_dotprod(cpu_flags)) {
c->lumToYV12 = ff_rgba32ToY_neon_dotprod;
}
#endif
if (c->chrSrcHSubSample)
c->chrToYV12 = ff_rgba32ToUV_half_neon;
else
c->chrToYV12 = ff_rgba32ToUV_neon;
break;
default:
break;
}
}
}
@@ -0,0 +1,223 @@
/*
* 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 "config.h"
#include "libswscale/swscale.h"
#include "libswscale/swscale_internal.h"
#include "libavutil/aarch64/cpu.h"
#define YUV_TO_RGB_TABLE \
c->yuv2rgb_v2r_coeff, \
c->yuv2rgb_u2g_coeff, \
c->yuv2rgb_v2g_coeff, \
c->yuv2rgb_u2b_coeff, \
#define DECLARE_FF_YUVX_TO_RGBX_FUNCS(ifmt, ofmt) \
int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \
uint8_t *dst, int linesize, \
const uint8_t *srcY, int linesizeY, \
const uint8_t *srcU, int linesizeU, \
const uint8_t *srcV, int linesizeV, \
const int16_t *table, \
int y_offset, \
int y_coeff); \
\
static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[], \
const int srcStride[], int srcSliceY, \
int srcSliceH, uint8_t *const dst[], \
const int dstStride[]) { \
const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \
\
return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH, \
dst[0] + srcSliceY * dstStride[0], dstStride[0], \
src[0], srcStride[0], \
src[1], srcStride[1], \
src[2], srcStride[2], \
yuv2rgb_table, \
c->yuv2rgb_y_offset >> 6, \
c->yuv2rgb_y_coeff); \
} \
#define DECLARE_FF_YUVX_TO_GBRP_FUNCS(ifmt, ofmt) \
int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \
uint8_t *dst, int linesize, \
const uint8_t *srcY, int linesizeY, \
const uint8_t *srcU, int linesizeU, \
const uint8_t *srcV, int linesizeV, \
const int16_t *table, \
int y_offset, \
int y_coeff, \
uint8_t *dst1, int linesize1, \
uint8_t *dst2, int linesize2); \
\
static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[], \
const int srcStride[], int srcSliceY, \
int srcSliceH, uint8_t *const dst[], \
const int dstStride[]) { \
const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \
\
return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH, \
dst[0] + srcSliceY * dstStride[0], dstStride[0], \
src[0], srcStride[0], \
src[1], srcStride[1], \
src[2], srcStride[2], \
yuv2rgb_table, \
c->yuv2rgb_y_offset >> 6, \
c->yuv2rgb_y_coeff, \
dst[1] + srcSliceY * dstStride[1], dstStride[1], \
dst[2] + srcSliceY * dstStride[2], dstStride[2]); \
} \
#define DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuvx) \
DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, argb) \
DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, rgba) \
DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, abgr) \
DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, bgra) \
DECLARE_FF_YUVX_TO_GBRP_FUNCS(yuvx, gbrp) \
DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv420p)
DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv422p)
#define DECLARE_FF_NVX_TO_RGBX_FUNCS(ifmt, ofmt) \
int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \
uint8_t *dst, int linesize, \
const uint8_t *srcY, int linesizeY, \
const uint8_t *srcC, int linesizeC, \
const int16_t *table, \
int y_offset, \
int y_coeff); \
\
static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[], \
const int srcStride[], int srcSliceY, \
int srcSliceH, uint8_t *const dst[], \
const int dstStride[]) { \
const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \
\
return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH, \
dst[0] + srcSliceY * dstStride[0], dstStride[0], \
src[0], srcStride[0], src[1], srcStride[1], \
yuv2rgb_table, \
c->yuv2rgb_y_offset >> 6, \
c->yuv2rgb_y_coeff); \
} \
#define DECLARE_FF_NVX_TO_GBRP_FUNCS(ifmt, ofmt) \
int ff_##ifmt##_to_##ofmt##_neon(int w, int h, \
uint8_t *dst, int linesize, \
const uint8_t *srcY, int linesizeY, \
const uint8_t *srcC, int linesizeC, \
const int16_t *table, \
int y_offset, \
int y_coeff, \
uint8_t *dst1, int linesize1, \
uint8_t *dst2, int linesize2); \
\
static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[], \
const int srcStride[], int srcSliceY, \
int srcSliceH, uint8_t *const dst[], \
const int dstStride[]) { \
const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE }; \
\
return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH, \
dst[0] + srcSliceY * dstStride[0], dstStride[0], \
src[0], srcStride[0], src[1], srcStride[1], \
yuv2rgb_table, \
c->yuv2rgb_y_offset >> 6, \
c->yuv2rgb_y_coeff, \
dst[1] + srcSliceY * dstStride[1], dstStride[1], \
dst[2] + srcSliceY * dstStride[2], dstStride[2]); \
} \
void ff_nv24_to_yuv420p_chroma_neon(uint8_t *dst1, int dstStride1,
uint8_t *dst2, int dstStride2,
const uint8_t *src, int srcStride,
int w, int h);
static int nv24_to_yuv420p_neon_wrapper(SwsInternal *c, const uint8_t *const src[],
const int srcStride[], int srcSliceY, int srcSliceH,
uint8_t *const dst[], const int dstStride[])
{
uint8_t *dst1 = dst[1] + dstStride[1] * srcSliceY / 2;
uint8_t *dst2 = dst[2] + dstStride[2] * srcSliceY / 2;
ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w,
dst[0], dstStride[0]);
if (c->opts.src_format == AV_PIX_FMT_NV24)
ff_nv24_to_yuv420p_chroma_neon(dst1, dstStride[1], dst2, dstStride[2],
src[1], srcStride[1], c->opts.src_w / 2,
srcSliceH);
else
ff_nv24_to_yuv420p_chroma_neon(dst2, dstStride[2], dst1, dstStride[1],
src[1], srcStride[1], c->opts.src_w / 2,
srcSliceH);
return srcSliceH;
}
#define DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nvx) \
DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, argb) \
DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, rgba) \
DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, abgr) \
DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, bgra) \
DECLARE_FF_NVX_TO_GBRP_FUNCS(nvx, gbrp) \
DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv12)
DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv21)
/* We need a 16 pixel width alignment. This constraint can easily be removed
* for input reading but for the output which is 4-bytes per pixel (RGBA) the
* assembly might be writing as much as 4*15=60 extra bytes at the end of the
* line, which won't fit the 32-bytes buffer alignment. */
#define SET_FF_NVX_TO_RGBX_FUNC(ifmt, IFMT, ofmt, OFMT, accurate_rnd) do { \
if (c->opts.src_format == AV_PIX_FMT_##IFMT \
&& c->opts.dst_format == AV_PIX_FMT_##OFMT \
&& !(c->opts.src_h & 1) \
&& !(c->opts.src_w & 15) \
&& !accurate_rnd) \
c->convert_unscaled = ifmt##_to_##ofmt##_neon_wrapper; \
} while (0)
#define SET_FF_NVX_TO_ALL_RGBX_FUNC(nvx, NVX, accurate_rnd) do { \
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, argb, ARGB, accurate_rnd); \
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, rgba, RGBA, accurate_rnd); \
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, abgr, ABGR, accurate_rnd); \
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, bgra, BGRA, accurate_rnd); \
SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, gbrp, GBRP, accurate_rnd); \
} while (0)
static void get_unscaled_swscale_neon(SwsInternal *c) {
int accurate_rnd = c->opts.flags & SWS_ACCURATE_RND;
SET_FF_NVX_TO_ALL_RGBX_FUNC(nv12, NV12, accurate_rnd);
SET_FF_NVX_TO_ALL_RGBX_FUNC(nv21, NV21, accurate_rnd);
SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv420p, YUV420P, accurate_rnd);
SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv422p, YUV422P, accurate_rnd);
if (c->opts.dst_format == AV_PIX_FMT_YUV420P &&
(c->opts.src_format == AV_PIX_FMT_NV24 || c->opts.src_format == AV_PIX_FMT_NV42) &&
!(c->opts.src_h & 1) && !(c->opts.src_w & 15) && !accurate_rnd)
c->convert_unscaled = nv24_to_yuv420p_neon_wrapper;
}
void ff_get_unscaled_swscale_aarch64(SwsInternal *c)
{
int cpu_flags = av_get_cpu_flags();
if (have_neon(cpu_flags))
get_unscaled_swscale_neon(c);
}
@@ -0,0 +1,70 @@
/*
* 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/aarch64/asm.S"
function ff_nv24_to_yuv420p_chroma_neon, export=1
// x0 uint8_t *dst1
// x1 int dstStride1
// x2 uint8_t *dst2
// x3 int dstStride2
// x4 const uint8_t *src
// x5 int srcStride
// w6 int w
// w7 int h
add x9, x4, w5, sxtw // x9 = src + srcStride
lsl w5, w5, #1 // srcStride *= 2
sub w5, w5, w6, lsl #2 // srcPadding = (2 * srcStride) - (4 * w)
sub w1, w1, w6 // dstPadding1 = dstStride1 - w
sub w3, w3, w6 // dstPadding2 = dstStride2 - w
1:
mov w10, w6 // w10 = w
2:
ld2 {v0.16b, v1.16b}, [x4], #32 // v0 = U1, v1 = V1
ld2 {v2.16b, v3.16b}, [x9], #32 // v2 = U2, v3 = V2
uaddlp v0.8h, v0.16b // pairwise add U1 into v0
uaddlp v1.8h, v1.16b // pairwise add V1 into v1
uadalp v0.8h, v2.16b // pairwise add U2, accumulate into v0
uadalp v1.8h, v3.16b // pairwise add V2, accumulate into v1
shrn v0.8b, v0.8h, #2 // divide by 4
shrn v1.8b, v1.8h, #2 // divide by 4
st1 {v0.8b}, [x0], #8 // store U into dst1
st1 {v1.8b}, [x2], #8 // store V into dst2
subs w10, w10, #8
b.gt 2b
// next row
add x4, x4, w5, sxtw // src1 += srcPadding
add x9, x9, w5, sxtw // src2 += srcPadding
add x0, x0, w1, sxtw // dst1 += dstPadding1
add x2, x2, w3, sxtw // dst2 += dstPadding2
subs w7, w7, #2
b.gt 1b
ret
endfunc
+259
View File
@@ -0,0 +1,259 @@
/*
* Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
* Copyright (c) 2016 Clément Bœsch <clement stupeflix.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/aarch64/asm.S"
.macro load_yoff_ycoeff yoff ycoeff
#if defined(__APPLE__)
ldp w9, w10, [sp, #\yoff]
#else
ldr w9, [sp, #\yoff]
ldr w10, [sp, #\ycoeff]
#endif
.endm
.macro load_dst1_dst2 dst1 linesize1 dst2 linesize2
#if defined(__APPLE__)
#define DST_OFFSET 8
#else
#define DST_OFFSET 0
#endif
ldr x10, [sp, #\dst1 - DST_OFFSET]
ldr w12, [sp, #\linesize1 - DST_OFFSET]
ldr x15, [sp, #\dst2 - DST_OFFSET]
ldr w16, [sp, #\linesize2 - DST_OFFSET]
#undef DST_OFFSET
sub w12, w12, w0 // w12 = linesize1 - width (padding1)
sub w16, w16, w0 // w16 = linesize2 - width (padding2)
.endm
.macro load_args_nv12 ofmt
ldr x8, [sp] // table
load_yoff_ycoeff 8, 16 // y_offset, y_coeff
ld1 {v1.1d}, [x8]
dup v0.8h, w10
dup v3.8h, w9
.ifc \ofmt,gbrp
load_dst1_dst2 24, 32, 40, 48
sub w3, w3, w0 // w3 = linesize - width (padding)
.else
sub w3, w3, w0, lsl #2 // w3 = linesize - width * 4 (padding)
.endif
sub w5, w5, w0 // w5 = linesizeY - width (paddingY)
sub w7, w7, w0 // w7 = linesizeC - width (paddingC)
neg w11, w0
.endm
.macro load_args_nv21 ofmt
load_args_nv12 \ofmt
.endm
.macro load_args_yuv420p ofmt
ldr x13, [sp] // srcV
ldr w14, [sp, #8] // linesizeV
ldr x8, [sp, #16] // table
load_yoff_ycoeff 24, 32 // y_offset, y_coeff
ld1 {v1.1d}, [x8]
dup v0.8h, w10
dup v3.8h, w9
.ifc \ofmt,gbrp
load_dst1_dst2 40, 48, 56, 64
sub w3, w3, w0 // w3 = linesize - width (padding)
.else
sub w3, w3, w0, lsl #2 // w3 = linesize - width * 4 (padding)
.endif
sub w5, w5, w0 // w5 = linesizeY - width (paddingY)
sub w7, w7, w0, lsr #1 // w7 = linesizeU - width / 2 (paddingU)
sub w14, w14, w0, lsr #1 // w14 = linesizeV - width / 2 (paddingV)
lsr w11, w0, #1
neg w11, w11
.endm
.macro load_args_yuv422p ofmt
ldr x13, [sp] // srcV
ldr w14, [sp, #8] // linesizeV
ldr x8, [sp, #16] // table
load_yoff_ycoeff 24, 32 // y_offset, y_coeff
ld1 {v1.1d}, [x8]
dup v0.8h, w10
dup v3.8h, w9
.ifc \ofmt,gbrp
load_dst1_dst2 40, 48, 56, 64
sub w3, w3, w0 // w3 = linesize - width (padding)
.else
sub w3, w3, w0, lsl #2 // w3 = linesize - width * 4 (padding)
.endif
sub w5, w5, w0 // w5 = linesizeY - width (paddingY)
sub w7, w7, w0, lsr #1 // w7 = linesizeU - width / 2 (paddingU)
sub w14, w14, w0, lsr #1 // w14 = linesizeV - width / 2 (paddingV)
.endm
.macro load_chroma_nv12
ld2 {v16.8b, v17.8b}, [x6], #16
ushll v18.8h, v16.8b, #3
ushll v19.8h, v17.8b, #3
.endm
.macro load_chroma_nv21
ld2 {v16.8b, v17.8b}, [x6], #16
ushll v19.8h, v16.8b, #3
ushll v18.8h, v17.8b, #3
.endm
.macro load_chroma_yuv420p
ld1 {v16.8b}, [ x6], #8
ld1 {v17.8b}, [x13], #8
ushll v18.8h, v16.8b, #3
ushll v19.8h, v17.8b, #3
.endm
.macro load_chroma_yuv422p
load_chroma_yuv420p
.endm
.macro increment_nv12
ands w17, w1, #1
csel w17, w7, w11, ne // incC = (h & 1) ? paddincC : -width
add x6, x6, w17, sxtw // srcC += incC
.endm
.macro increment_nv21
increment_nv12
.endm
.macro increment_yuv420p
ands w17, w1, #1
csel w17, w7, w11, ne // incU = (h & 1) ? paddincU : -width/2
add x6, x6, w17, sxtw // srcU += incU
csel w17, w14, w11, ne // incV = (h & 1) ? paddincV : -width/2
add x13, x13, w17, sxtw // srcV += incV
.endm
.macro increment_yuv422p
add x6, x6, w7, sxtw // srcU += incU
add x13, x13, w14, sxtw // srcV += incV
.endm
.macro compute_rgb r1 g1 b1 r2 g2 b2
add v20.8h, v26.8h, v20.8h // Y1 + R1
add v21.8h, v27.8h, v21.8h // Y2 + R2
add v22.8h, v26.8h, v22.8h // Y1 + G1
add v23.8h, v27.8h, v23.8h // Y2 + G2
add v24.8h, v26.8h, v24.8h // Y1 + B1
add v25.8h, v27.8h, v25.8h // Y2 + B2
sqrshrun \r1, v20.8h, #1 // clip_u8((Y1 + R1) >> 1)
sqrshrun \r2, v21.8h, #1 // clip_u8((Y2 + R1) >> 1)
sqrshrun \g1, v22.8h, #1 // clip_u8((Y1 + G1) >> 1)
sqrshrun \g2, v23.8h, #1 // clip_u8((Y2 + G1) >> 1)
sqrshrun \b1, v24.8h, #1 // clip_u8((Y1 + B1) >> 1)
sqrshrun \b2, v25.8h, #1 // clip_u8((Y2 + B1) >> 1)
.endm
.macro compute_rgba r1 g1 b1 a1 r2 g2 b2 a2
compute_rgb \r1, \g1, \b1, \r2, \g2, \b2
movi \a1, #255
movi \a2, #255
.endm
.macro declare_func ifmt ofmt
function ff_\ifmt\()_to_\ofmt\()_neon, export=1
load_args_\ifmt \ofmt
mov w9, w1
1:
mov w8, w0 // w8 = width
2:
movi v5.8h, #4, lsl #8 // 128 * (1<<3)
load_chroma_\ifmt
sub v18.8h, v18.8h, v5.8h // U*(1<<3) - 128*(1<<3)
sub v19.8h, v19.8h, v5.8h // V*(1<<3) - 128*(1<<3)
sqdmulh v20.8h, v19.8h, v1.h[0] // V * v2r (R)
sqdmulh v22.8h, v18.8h, v1.h[1] // U * u2g
sqdmulh v19.8h, v19.8h, v1.h[2] // V * v2g
add v22.8h, v22.8h, v19.8h // U * u2g + V * v2g (G)
sqdmulh v24.8h, v18.8h, v1.h[3] // U * u2b (B)
zip2 v21.8h, v20.8h, v20.8h // R2
zip1 v20.8h, v20.8h, v20.8h // R1
zip2 v23.8h, v22.8h, v22.8h // G2
zip1 v22.8h, v22.8h, v22.8h // G1
zip2 v25.8h, v24.8h, v24.8h // B2
zip1 v24.8h, v24.8h, v24.8h // B1
ld1 {v2.16b}, [x4], #16 // load luma
ushll v26.8h, v2.8b, #3 // Y1*(1<<3)
ushll2 v27.8h, v2.16b, #3 // Y2*(1<<3)
sub v26.8h, v26.8h, v3.8h // Y1*(1<<3) - y_offset
sub v27.8h, v27.8h, v3.8h // Y2*(1<<3) - y_offset
sqdmulh v26.8h, v26.8h, v0.8h // ((Y1*(1<<3) - y_offset) * y_coeff) >> 15
sqdmulh v27.8h, v27.8h, v0.8h // ((Y2*(1<<3) - y_offset) * y_coeff) >> 15
.ifc \ofmt,argb // 1 2 3 0
compute_rgba v5.8b,v6.8b,v7.8b,v4.8b, v17.8b,v18.8b,v19.8b,v16.8b
.endif
.ifc \ofmt,rgba // 0 1 2 3
compute_rgba v4.8b,v5.8b,v6.8b,v7.8b, v16.8b,v17.8b,v18.8b,v19.8b
.endif
.ifc \ofmt,abgr // 3 2 1 0
compute_rgba v7.8b,v6.8b,v5.8b,v4.8b, v19.8b,v18.8b,v17.8b,v16.8b
.endif
.ifc \ofmt,bgra // 2 1 0 3
compute_rgba v6.8b,v5.8b,v4.8b,v7.8b, v18.8b,v17.8b,v16.8b,v19.8b
.endif
.ifc \ofmt,gbrp
compute_rgb v18.8b,v4.8b,v6.8b, v19.8b,v5.8b,v7.8b
st1 { v4.8b, v5.8b }, [x2], #16
st1 { v6.8b, v7.8b }, [x10], #16
st1 { v18.8b, v19.8b }, [x15], #16
.else
st4 { v4.8b, v5.8b, v6.8b, v7.8b}, [x2], #32
st4 {v16.8b,v17.8b,v18.8b,v19.8b}, [x2], #32
.endif
subs w8, w8, #16 // width -= 16
b.gt 2b
add x2, x2, w3, sxtw // dst += padding
.ifc \ofmt,gbrp
add x10, x10, w12, sxtw // dst1 += padding1
add x15, x15, w16, sxtw // dst2 += padding2
.endif
add x4, x4, w5, sxtw // srcY += paddingY
increment_\ifmt
subs w1, w1, #1 // height -= 1
b.gt 1b
mov w0, w9
ret
endfunc
.endm
.macro declare_rgb_funcs ifmt
declare_func \ifmt, argb
declare_func \ifmt, rgba
declare_func \ifmt, abgr
declare_func \ifmt, bgra
declare_func \ifmt, gbrp
.endm
declare_rgb_funcs nv12
declare_rgb_funcs nv21
declare_rgb_funcs yuv420p
declare_rgb_funcs yuv422p