- ff_pix_abs16_neon - ff_pix_abs16_xy2_neon In direct micro benchmarks of these ff functions verses their C implementations, these functions performed as follows on AWS Graviton 3. ff_pix_abs16_neon: pix_abs_0_0_c: 141.1 pix_abs_0_0_neon: 19.6 ff_pix_abs16_xy2_neon: pix_abs_0_3_c: 269.1 pix_abs_0_3_neon: 39.3 Tested with: ./tests/checkasm/checkasm --test=motion --bench --disable-linux-perf
Unified · Split
| @@ -7,6 +7,7 @@ OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_init.o · 6 unmodified lines | |||
| 7 | OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_init_aarch64.o | 7 | OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_init_aarch64.o |
| 8 | OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o | 8 | OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o |
| 9 | OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o | 9 | OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o |
| 10 | OBJS-$(CONFIG_ME_CMP) += aarch64/me_cmp_init_aarch64.o | ||
| 10 | OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o | 11 | OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o |
| 11 | OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o | 12 | OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o |
| 12 | OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_init_aarch64.o | 13 | OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_init_aarch64.o |
| @@ -47,6 +48,7 @@ NEON-OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_neon.o · 34 unmodified lines | |||
| 47 | NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_neon.o \ | 48 | NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_neon.o \ |
| 48 | aarch64/simple_idct_neon.o | 49 | aarch64/simple_idct_neon.o |
| 49 | NEON-OBJS-$(CONFIG_MDCT) += aarch64/mdct_neon.o | 50 | NEON-OBJS-$(CONFIG_MDCT) += aarch64/mdct_neon.o |
| 51 | NEON-OBJS-$(CONFIG_ME_CMP) += aarch64/me_cmp_neon.o | ||
| 50 | NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o | 52 | NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o |
| 51 | NEON-OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_neon.o | 53 | NEON-OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_neon.o |
| 52 | NEON-OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_neon.o | 54 | NEON-OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_neon.o |
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <stdint.h> | ||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | #include "libavutil/attributes.h" | ||
| 23 | #include "libavutil/aarch64/cpu.h" | ||
| 24 | #include "libavcodec/mpegvideo.h" | ||
| 25 | |||
| 26 | int ff_pix_abs16_neon(MpegEncContext *s, uint8_t *blk1, uint8_t *blk2, | ||
| 27 | ptrdiff_t stride, int h); | ||
| 28 | int ff_pix_abs16_xy2_neon(MpegEncContext *s, uint8_t *blk1, uint8_t *blk2, | ||
| 29 | ptrdiff_t stride, int h); | ||
| 30 | |||
| 31 | av_cold void ff_me_cmp_init_aarch64(MECmpContext *c, AVCodecContext *avctx) | ||
| 32 | { | ||
| 33 | int cpu_flags = av_get_cpu_flags(); | ||
| 34 | |||
| 35 | if (have_neon(cpu_flags)) { | ||
| 36 | c->pix_abs[0][0] = ff_pix_abs16_neon; | ||
| 37 | c->pix_abs[0][3] = ff_pix_abs16_xy2_neon; | ||
| 38 | } | ||
| 39 | } | ||
| @@ -0,0 +1,205 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2022 Jonathan Swinney <jswinney@amazon.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "libavutil/aarch64/asm.S" | ||
| 22 | |||
| 23 | function ff_pix_abs16_neon, export=1 | ||
| 24 | // x0 unused | ||
| 25 | // x1 uint8_t *pix1 | ||
| 26 | // x2 uint8_t *pix2 | ||
| 27 | // x3 ptrdiff_t stride | ||
| 28 | // w4 int h | ||
| 29 | cmp w4, #4 // if h < 4, jump to completion section | ||
| 30 | movi v18.4S, #0 // clear result accumulator | ||
| 31 | b.lt 2f | ||
| 32 | 1: | ||
| 33 | ld1 {v0.16b}, [x1], x3 // load pix1 | ||
| 34 | ld1 {v4.16b}, [x2], x3 // load pix2 | ||
| 35 | ld1 {v1.16b}, [x1], x3 // load pix1 | ||
| 36 | ld1 {v5.16b}, [x2], x3 // load pix2 | ||
| 37 | uabdl v16.8h, v0.8b, v4.8b // absolute difference accumulate | ||
| 38 | uabdl2 v17.8h, v0.16b, v4.16b | ||
| 39 | ld1 {v2.16b}, [x1], x3 // load pix1 | ||
| 40 | ld1 {v6.16b}, [x2], x3 // load pix2 | ||
| 41 | uabal v16.8h, v1.8b, v5.8b // absolute difference accumulate | ||
| 42 | uabal2 v17.8h, v1.16b, v5.16b | ||
| 43 | ld1 {v3.16b}, [x1], x3 | ||
| 44 | ld1 {v7.16b}, [x2], x3 | ||
| 45 | uabal v16.8h, v2.8b, v6.8b | ||
| 46 | uabal2 v17.8h, v2.16b, v6.16b | ||
| 47 | sub w4, w4, #4 // h -= 4 | ||
| 48 | uabal v16.8h, v3.8b, v7.8b | ||
| 49 | uabal2 v17.8h, v3.16b, v7.16b | ||
| 50 | cmp w4, #4 // if h >= 4, loop | ||
| 51 | add v16.8h, v16.8h, v17.8h | ||
| 52 | uaddlv s16, v16.8h // add up everything in v16 accumulator | ||
| 53 | add d18, d16, d18 // add to the end result register | ||
| 54 | |||
| 55 | b.ge 1b | ||
| 56 | cbnz w4, 2f // if iterations remain, jump to completion section | ||
| 57 | |||
| 58 | fmov w0, s18 // copy result to general purpose register | ||
| 59 | ret | ||
| 60 | |||
| 61 | 2: | ||
| 62 | ld1 {v0.16b}, [x1], x3 // load pix1 | ||
| 63 | ld1 {v4.16b}, [x2], x3 // load pix2 | ||
| 64 | uabdl v16.8h, v0.8b, v4.8b // absolute difference accumulate | ||
| 65 | uabal2 v16.8h, v0.16b, v4.16b | ||
| 66 | subs w4, w4, #1 // h -= 1 | ||
| 67 | addv h16, v16.8h // add up v16 | ||
| 68 | add d18, d16, d18 // add to result | ||
| 69 | b.ne 2b | ||
| 70 | |||
| 71 | fmov w0, s18 // copy result to general purpose register | ||
| 72 | ret | ||
| 73 | endfunc | ||
| 74 | |||
| 75 | function ff_pix_abs16_xy2_neon, export=1 | ||
| 76 | // x0 unused | ||
| 77 | // x1 uint8_t *pix1 | ||
| 78 | // x2 uint8_t *pix2 | ||
| 79 | // x3 ptrdiff_t stride | ||
| 80 | // w4 int h | ||
| 81 | |||
| 82 | add x5, x2, x3 // use x5 to hold uint8_t *pix3 | ||
| 83 | movi v0.2d, #0 // initialize the result register | ||
| 84 | |||
| 85 | // Load initial pix2 values for either the unrolled version or completion version. | ||
| 86 | ldur q4, [x2, #1] // load pix2+1 | ||
| 87 | ldr q3, [x2] // load pix2 | ||
| 88 | uaddl v2.8h, v4.8b, v3.8b // pix2 + pix2+1 0..7 | ||
| 89 | uaddl2 v3.8h, v4.16b, v3.16b // pix2 + pix2+1 8..15 | ||
| 90 | cmp w4, #4 // if h < 4 jump to the completion version | ||
| 91 | b.lt 2f | ||
| 92 | 1: | ||
| 93 | // This is an unrolled implementation. It completes 4 iterations of the C for each branch. | ||
| 94 | // In each iteration, pix2[i+1] == pix3[i]. This means we need only three loads per iteration, | ||
| 95 | // plus two at the beginning to start. | ||
| 96 | ldur q5, [x5, #1] // load pix3+1 | ||
| 97 | ld1 {v4.16b}, [x5], x3 // load pix3 | ||
| 98 | ld1 {v1.16b}, [x1], x3 // load pix1 | ||
| 99 | |||
| 100 | ldur q7, [x5, #1] // load pix3+1 | ||
| 101 | ld1 {v6.16b}, [x5], x3 // load pix3 | ||
| 102 | ld1 {v16.16b}, [x1], x3 // load pix1 | ||
| 103 | |||
| 104 | ldur q19, [x5, #1] // load pix3+1 | ||
| 105 | ld1 {v18.16b}, [x5], x3 // load pix3 | ||
| 106 | ld1 {v17.16b}, [x1], x3 // load pix1 | ||
| 107 | |||
| 108 | ldur q22, [x5, #1] // load pix3+1 | ||
| 109 | ld1 {v21.16b}, [x5], x3 // load pix3 | ||
| 110 | ld1 {v20.16b}, [x1], x3 // load pix1 | ||
| 111 | |||
| 112 | // These blocks compute the average: avg(pix2[n], pix2[n+1], pix3[n], pix3[n+1]) | ||
| 113 | uaddl v30.8h, v4.8b, v5.8b // pix3 + pix3+1 0..7 | ||
| 114 | uaddl2 v31.8h, v4.16b, v5.16b // pix3 + pix3+1 8..15 | ||
| 115 | add v23.8h, v2.8h, v30.8h // add up 0..7, using pix2 + pix2+1 values from previous iteration | ||
| 116 | add v24.8h, v3.8h, v31.8h // add up 8..15, using pix2 + pix2+1 values from previous iteration | ||
| 117 | rshrn v23.8b, v23.8h, #2 // shift right 2 0..7 (rounding shift right) | ||
| 118 | rshrn2 v23.16b, v24.8h, #2 // shift right 2 8..15 | ||
| 119 | |||
| 120 | uaddl v2.8h, v6.8b, v7.8b // pix3 + pix3+1 0..7 | ||
| 121 | uaddl2 v3.8h, v6.16b, v7.16b // pix3 + pix3+1 8..15 | ||
| 122 | add v26.8h, v30.8h, v2.8h // add up 0..7, using pix2 + pix2+1 values from pix3 above | ||
| 123 | add v27.8h, v31.8h, v3.8h // add up 8..15, using pix2 + pix2+1 values from pix3 above | ||
| 124 | rshrn v26.8b, v26.8h, #2 // shift right 2 0..7 (rounding shift right) | ||
| 125 | rshrn2 v26.16b, v27.8h, #2 // shift right 2 8..15 | ||
| 126 | |||
| 127 | uaddl v4.8h, v18.8b, v19.8b // pix3 + pix3+1 0..7 | ||
| 128 | uaddl2 v5.8h, v18.16b, v19.16b // pix3 + pix3+1 8..15 | ||
| 129 | add v28.8h, v2.8h, v4.8h // add up 0..7, using pix2 + pix2+1 values from pix3 above | ||
| 130 | add v29.8h, v3.8h, v5.8h // add up 8..15, using pix2 + pix2+1 values from pix3 above | ||
| 131 | rshrn v28.8b, v28.8h, #2 // shift right 2 0..7 (rounding shift right) | ||
| 132 | rshrn2 v28.16b, v29.8h, #2 // shift right 2 8..15 | ||
| 133 | |||
| 134 | uaddl v2.8h, v21.8b, v22.8b // pix3 + pix3+1 0..7 | ||
| 135 | uaddl2 v3.8h, v21.16b, v22.16b // pix3 + pix3+1 8..15 | ||
| 136 | add v30.8h, v4.8h, v2.8h // add up 0..7, using pix2 + pix2+1 values from pix3 above | ||
| 137 | add v31.8h, v5.8h, v3.8h // add up 8..15, using pix2 + pix2+1 values from pix3 above | ||
| 138 | rshrn v30.8b, v30.8h, #2 // shift right 2 0..7 (rounding shift right) | ||
| 139 | rshrn2 v30.16b, v31.8h, #2 // shift right 2 8..15 | ||
| 140 | |||
| 141 | // Averages are now stored in these registers: | ||
| 142 | // v23, v16, v28, v30 | ||
| 143 | // pix1 values in these registers: | ||
| 144 | // v1, v16, v17, v20 | ||
| 145 | // available: | ||
| 146 | // v4, v5, v7, v18, v19, v24, v25, v27, v29, v31 | ||
| 147 | |||
| 148 | sub w4, w4, #4 // h -= 4 | ||
| 149 | |||
| 150 | // Using absolute-difference instructions instead of absolute-difference-accumulate allows | ||
| 151 | // us to keep the results in 16b vectors instead of widening values with twice the instructions. | ||
| 152 | // This approach also has fewer data dependencies, allowing better instruction level parallelism. | ||
| 153 | uabd v4.16b, v1.16b, v23.16b // absolute difference 0..15, i=0 | ||
| 154 | uabd v5.16b, v16.16b, v26.16b // absolute difference 0..15, i=1 | ||
| 155 | uabd v6.16b, v17.16b, v28.16b // absolute difference 0..15, i=2 | ||
| 156 | uabd v7.16b, v20.16b, v30.16b // absolute difference 0..15, i=3 | ||
| 157 | |||
| 158 | cmp w4, #4 // loop if h >= 4 | ||
| 159 | |||
| 160 | // Now add up all the values in each vector, v4-v7 with widening adds | ||
| 161 | uaddl v19.8h, v4.8b, v5.8b | ||
| 162 | uaddl2 v18.8h, v4.16b, v5.16b | ||
| 163 | uaddl v4.8h, v6.8b, v7.8b | ||
| 164 | uaddl2 v5.8h, v6.16b, v7.16b | ||
| 165 | add v4.8h, v4.8h, v5.8h | ||
| 166 | add v4.8h, v4.8h, v18.8h | ||
| 167 | add v4.8h, v4.8h, v19.8h | ||
| 168 | uaddlv s4, v4.8h // finish adding up accumulated values | ||
| 169 | add d0, d0, d4 // add the value to the top level accumulator | ||
| 170 | |||
| 171 | b.ge 1b | ||
| 172 | cbnz w4, 2f // if iterations remain jump to completion section | ||
| 173 | |||
| 174 | fmov w0, s0 // copy result to general purpose register | ||
| 175 | ret | ||
| 176 | 2: | ||
| 177 | // v2 and v3 are set either at the end of this loop or at from the unrolled version | ||
| 178 | // which branches here to complete iterations when h % 4 != 0. | ||
| 179 | ldur q5, [x5, #1] // load pix3+1 | ||
| 180 | ld1 {v4.16b}, [x5], x3 // load pix3 | ||
| 181 | ld1 {v1.16b}, [x1], x3 // load pix1 | ||
| 182 | subs w4, w4, #1 // decrement h | ||
| 183 | |||
| 184 | uaddl v18.8h, v4.8b, v5.8b // pix3 + pix3+1 0..7 | ||
| 185 | uaddl2 v19.8h, v4.16b, v5.16b // pix3 + pix3+1 8..15 | ||
| 186 | add v16.8h, v2.8h, v18.8h // add up 0..7, using pix2 + pix2+1 values from previous iteration | ||
| 187 | add v17.8h, v3.8h, v19.8h // add up 8..15, using pix2 + pix2+1 values from previous iteration | ||
| 188 | // divide by 4 to compute the average of values summed above | ||
| 189 | urshr v16.8h, v16.8h, #2 // shift right by 2 0..7 (rounding shift right) | ||
| 190 | urshr v17.8h, v17.8h, #2 // shift right by 2 8..15 | ||
| 191 | |||
| 192 | uxtl2 v8.8h, v1.16b // 8->16 bits pix1 8..15 | ||
| 193 | uxtl v1.8h, v1.8b // 8->16 bits pix1 0..7 | ||
| 194 | |||
| 195 | uabd v6.8h, v1.8h, v16.8h // absolute difference 0..7 | ||
| 196 | uaba v6.8h, v8.8h, v17.8h // absolute difference accumulate 8..15 | ||
| 197 | mov v2.16b, v18.16b // pix3 -> pix2 | ||
| 198 | mov v3.16b, v19.16b // pix3+1 -> pix2+1 | ||
| 199 | uaddlv s6, v6.8h // add up accumulator in v6 | ||
| 200 | add d0, d0, d6 // add to the final result | ||
| 201 | |||
| 202 | b.ne 2b // loop if h > 0 | ||
| 203 | fmov w0, s0 // copy result to general purpose register | ||
| 204 | ret | ||
| 205 | endfunc | ||
| @@ -1061,7 +1061,9 @@ av_cold void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx) · 1060 unmodified lines | |||
| 1061 | ff_dsputil_init_dwt(c); | 1061 | ff_dsputil_init_dwt(c); |
| 1062 | #endif | 1062 | #endif |
| 1063 | 1063 | ||
| 1064 | #if ARCH_ALPHA | 1064 | #if ARCH_AARCH64 |
| 1065 | ff_me_cmp_init_aarch64(c, avctx); | ||
| 1066 | #elif ARCH_ALPHA | ||
| 1065 | ff_me_cmp_init_alpha(c, avctx); | 1067 | ff_me_cmp_init_alpha(c, avctx); |
| 1066 | #elif ARCH_ARM | 1068 | #elif ARCH_ARM |
| 1067 | ff_me_cmp_init_arm(c, avctx); | 1069 | ff_me_cmp_init_arm(c, avctx); |
| @@ -80,6 +80,7 @@ typedef struct MECmpContext { · 79 unmodified lines | |||
| 80 | } MECmpContext; | 80 | } MECmpContext; |
| 81 | 81 | ||
| 82 | void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx); | 82 | void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx); |
| 83 | void ff_me_cmp_init_aarch64(MECmpContext *c, AVCodecContext *avctx); | ||
| 83 | void ff_me_cmp_init_alpha(MECmpContext *c, AVCodecContext *avctx); | 84 | void ff_me_cmp_init_alpha(MECmpContext *c, AVCodecContext *avctx); |
| 84 | void ff_me_cmp_init_arm(MECmpContext *c, AVCodecContext *avctx); | 85 | void ff_me_cmp_init_arm(MECmpContext *c, AVCodecContext *avctx); |
| 85 | void ff_me_cmp_init_ppc(MECmpContext *c, AVCodecContext *avctx); | 86 | void ff_me_cmp_init_ppc(MECmpContext *c, AVCodecContext *avctx); |
| @@ -12,6 +12,7 @@ AVCODECOBJS-$(CONFIG_H264QPEL) += h264qpel.o · 11 unmodified lines | |||
| 12 | AVCODECOBJS-$(CONFIG_IDCTDSP) += idctdsp.o | 12 | AVCODECOBJS-$(CONFIG_IDCTDSP) += idctdsp.o |
| 13 | AVCODECOBJS-$(CONFIG_LLVIDDSP) += llviddsp.o | 13 | AVCODECOBJS-$(CONFIG_LLVIDDSP) += llviddsp.o |
| 14 | AVCODECOBJS-$(CONFIG_LLVIDENCDSP) += llviddspenc.o | 14 | AVCODECOBJS-$(CONFIG_LLVIDENCDSP) += llviddspenc.o |
| 15 | AVCODECOBJS-$(CONFIG_ME_CMP) += motion.o | ||
| 15 | AVCODECOBJS-$(CONFIG_VC1DSP) += vc1dsp.o | 16 | AVCODECOBJS-$(CONFIG_VC1DSP) += vc1dsp.o |
| 16 | AVCODECOBJS-$(CONFIG_VP8DSP) += vp8dsp.o | 17 | AVCODECOBJS-$(CONFIG_VP8DSP) += vp8dsp.o |
| 17 | AVCODECOBJS-$(CONFIG_VIDEODSP) += videodsp.o | 18 | AVCODECOBJS-$(CONFIG_VIDEODSP) += videodsp.o |
| @@ -135,6 +135,9 @@ static const struct { · 134 unmodified lines | |||
| 135 | #if CONFIG_LLVIDENCDSP | 135 | #if CONFIG_LLVIDENCDSP |
| 136 | { "llviddspenc", checkasm_check_llviddspenc }, | 136 | { "llviddspenc", checkasm_check_llviddspenc }, |
| 137 | #endif | 137 | #endif |
| 138 | #if CONFIG_ME_CMP | ||
| 139 | { "motion", checkasm_check_motion }, | ||
| 140 | #endif | ||
| 138 | #if CONFIG_OPUS_DECODER | 141 | #if CONFIG_OPUS_DECODER |
| 139 | { "opusdsp", checkasm_check_opusdsp }, | 142 | { "opusdsp", checkasm_check_opusdsp }, |
| 140 | #endif | 143 | #endif |
| @@ -68,6 +68,7 @@ void checkasm_check_idctdsp(void); · 67 unmodified lines | |||
| 68 | void checkasm_check_jpeg2000dsp(void); | 68 | void checkasm_check_jpeg2000dsp(void); |
| 69 | void checkasm_check_llviddsp(void); | 69 | void checkasm_check_llviddsp(void); |
| 70 | void checkasm_check_llviddspenc(void); | 70 | void checkasm_check_llviddspenc(void); |
| 71 | void checkasm_check_motion(void); | ||
| 71 | void checkasm_check_nlmeans(void); | 72 | void checkasm_check_nlmeans(void); |
| 72 | void checkasm_check_opusdsp(void); | 73 | void checkasm_check_opusdsp(void); |
| 73 | void checkasm_check_pixblockdsp(void); | 74 | void checkasm_check_pixblockdsp(void); |
| @@ -0,0 +1,151 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * This file is part of FFmpeg. | ||
| 4 | * | ||
| 5 | * FFmpeg is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License along | ||
| 16 | * with FFmpeg; if not, write to the Free Software Foundation, Inc., | ||
| 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <string.h> | ||
| 21 | |||
| 22 | #include "libavutil/common.h" | ||
| 23 | #include "libavutil/intreadwrite.h" | ||
| 24 | #include "libavutil/mem_internal.h" | ||
| 25 | |||
| 26 | #include "libavcodec/me_cmp.h" | ||
| 27 | |||
| 28 | #include "checkasm.h" | ||
| 29 | |||
| 30 | static void fill_random(uint8_t *tab, int size) | ||
| 31 | { | ||
| 32 | int i; | ||
| 33 | for (i = 0; i < size; i++) { | ||
| 34 | tab[i] = rnd() % 256; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | static void test_motion(const char *name, me_cmp_func test_func) | ||
| 39 | { | ||
| 40 | /* test configurarion */ | ||
| 41 | #define ITERATIONS 16 | ||
| 42 | #define WIDTH 64 | ||
| 43 | #define HEIGHT 64 | ||
| 44 | |||
| 45 | /* motion estimation can look up to 17 bytes ahead */ | ||
| 46 | static const int look_ahead = 17; | ||
| 47 | |||
| 48 | int i, x, y, d1, d2; | ||
| 49 | uint8_t *ptr; | ||
| 50 | |||
| 51 | LOCAL_ALIGNED_8(uint8_t, img1, [WIDTH * HEIGHT]); | ||
| 52 | LOCAL_ALIGNED_8(uint8_t, img2, [WIDTH * HEIGHT]); | ||
| 53 | |||
| 54 | declare_func_emms(AV_CPU_FLAG_MMX, int, struct MpegEncContext *c, | ||
| 55 | uint8_t *blk1 /* align width (8 or 16) */, | ||
| 56 | uint8_t *blk2 /* align 1 */, ptrdiff_t stride, | ||
| 57 | int h); | ||
| 58 | |||
| 59 | if (test_func == NULL) { | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 63 | /* test correctness */ | ||
| 64 | fill_random(img1, WIDTH * HEIGHT); | ||
| 65 | fill_random(img2, WIDTH * HEIGHT); | ||
| 66 | |||
| 67 | if (check_func(test_func, "%s", name)) { | ||
| 68 | for (i = 0; i < ITERATIONS; i++) { | ||
| 69 | x = rnd() % (WIDTH - look_ahead); | ||
| 70 | y = rnd() % (HEIGHT - look_ahead); | ||
| 71 | |||
| 72 | ptr = img2 + y * WIDTH + x; | ||
| 73 | d2 = call_ref(NULL, img1, ptr, WIDTH, 8); | ||
| 74 | d1 = call_new(NULL, img1, ptr, WIDTH, 8); | ||
| 75 | |||
| 76 | if (d1 != d2) { | ||
| 77 | fail(); | ||
| 78 | printf("func: %s, x=%d y=%d, error: asm=%d c=%d\n", name, x, y, d1, d2); | ||
| 79 | break; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | // benchmark with the final value of ptr | ||
| 83 | bench_new(NULL, img1, ptr, WIDTH, 8); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | #define ME_CMP_1D_ARRAYS(XX) \ | ||
| 88 | XX(sad) \ | ||
| 89 | XX(sse) \ | ||
| 90 | XX(hadamard8_diff) \ | ||
| 91 | XX(vsad) \ | ||
| 92 | XX(vsse) \ | ||
| 93 | XX(nsse) \ | ||
| 94 | XX(me_pre_cmp) \ | ||
| 95 | XX(me_cmp) \ | ||
| 96 | XX(me_sub_cmp) \ | ||
| 97 | XX(mb_cmp) \ | ||
| 98 | XX(ildct_cmp) \ | ||
| 99 | XX(frame_skip_cmp) \ | ||
| 100 | XX(median_sad) | ||
| 101 | |||
| 102 | // tests for functions not yet implemented | ||
| 103 | #if 0 | ||
| 104 | XX(dct_sad) \ | ||
| 105 | XX(quant_psnr) \ | ||
| 106 | XX(bit) \ | ||
| 107 | XX(rd) \ | ||
| 108 | XX(w53) \ | ||
| 109 | XX(w97) \ | ||
| 110 | XX(dct_max) \ | ||
| 111 | XX(dct264_sad) \ | ||
| 112 | |||
| 113 | #endif | ||
| 114 | |||
| 115 | static void check_motion(void) | ||
| 116 | { | ||
| 117 | char buf[64]; | ||
| 118 | AVCodecContext *av_ctx; | ||
| 119 | MECmpContext me_ctx; | ||
| 120 | |||
| 121 | memset(&me_ctx, 0, sizeof(me_ctx)); | ||
| 122 | |||
| 123 | /* allocate AVCodecContext */ | ||
| 124 | av_ctx = avcodec_alloc_context3(NULL); | ||
| 125 | av_ctx->flags |= AV_CODEC_FLAG_BITEXACT; | ||
| 126 | |||
| 127 | ff_me_cmp_init(&me_ctx, av_ctx); | ||
| 128 | |||
| 129 | for (int i = 0; i < FF_ARRAY_ELEMS(me_ctx.pix_abs); i++) { | ||
| 130 | for (int j = 0; j < FF_ARRAY_ELEMS(me_ctx.pix_abs[0]); j++) { | ||
| 131 | snprintf(buf, sizeof(buf), "pix_abs_%d_%d", i, j); | ||
| 132 | test_motion(buf, me_ctx.pix_abs[i][j]); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | #define XX(me_cmp_array) \ | ||
| 137 | for (int i = 0; i < FF_ARRAY_ELEMS(me_ctx.me_cmp_array); i++) { \ | ||
| 138 | snprintf(buf, sizeof(buf), #me_cmp_array "_%d", i); \ | ||
| 139 | test_motion(buf, me_ctx.me_cmp_array[i]); \ | ||
| 140 | } | ||
| 141 | ME_CMP_1D_ARRAYS(XX) | ||
| 142 | #undef XX | ||
| 143 | |||
| 144 | avcodec_free_context(&av_ctx); | ||
| 145 | } | ||
| 146 | |||
| 147 | void checkasm_check_motion(void) | ||
| 148 | { | ||
| 149 | check_motion(); | ||
| 150 | report("motion"); | ||
| 151 | } | ||
| @@ -23,6 +23,7 @@ FATE_CHECKASM = fate-checkasm-aacpsdsp \ · 22 unmodified lines | |||
| 23 | fate-checkasm-jpeg2000dsp \ | 23 | fate-checkasm-jpeg2000dsp \ |
| 24 | fate-checkasm-llviddsp \ | 24 | fate-checkasm-llviddsp \ |
| 25 | fate-checkasm-llviddspenc \ | 25 | fate-checkasm-llviddspenc \ |
| 26 | fate-checkasm-motion \ | ||
| 26 | fate-checkasm-opusdsp \ | 27 | fate-checkasm-opusdsp \ |
| 27 | fate-checkasm-pixblockdsp \ | 28 | fate-checkasm-pixblockdsp \ |
| 28 | fate-checkasm-sbrdsp \ | 29 | fate-checkasm-sbrdsp \ |