- 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 | 7 | OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_init_aarch64.o |
| 8 | 8 | OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o |
| 9 | 9 | OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o |
| 10 | +OBJS-$(CONFIG_ME_CMP) += aarch64/me_cmp_init_aarch64.o | |
| 10 | 11 | OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o |
| 11 | 12 | OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o |
| 12 | 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 | 48 | NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_neon.o \ |
| 48 | 49 | aarch64/simple_idct_neon.o |
| 49 | 50 | NEON-OBJS-$(CONFIG_MDCT) += aarch64/mdct_neon.o |
| 51 | +NEON-OBJS-$(CONFIG_ME_CMP) += aarch64/me_cmp_neon.o | |
| 50 | 52 | NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o |
| 51 | 53 | NEON-OBJS-$(CONFIG_PIXBLOCKDSP) += aarch64/pixblockdsp_neon.o |
| 52 | 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 | 1061 | ff_dsputil_init_dwt(c); |
| 1062 | 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 | 1067 | ff_me_cmp_init_alpha(c, avctx); |
| 1066 | 1068 | #elif ARCH_ARM |
| 1067 | 1069 | ff_me_cmp_init_arm(c, avctx); |
| @@ -80,6 +80,7 @@ typedef struct MECmpContext { · 79 unmodified lines | ||
| 80 | 80 | } MECmpContext; |
| 81 | 81 | |
| 82 | 82 | void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx); |
| 83 | +void ff_me_cmp_init_aarch64(MECmpContext *c, AVCodecContext *avctx); | |
| 83 | 84 | void ff_me_cmp_init_alpha(MECmpContext *c, AVCodecContext *avctx); |
| 84 | 85 | void ff_me_cmp_init_arm(MECmpContext *c, AVCodecContext *avctx); |
| 85 | 86 | void ff_me_cmp_init_ppc(MECmpContext *c, AVCodecContext *avctx); |
| @@ -12,6 +12,7 @@ AVCODECOBJS-$(CONFIG_H264QPEL) += h264qpel.o · 11 unmodified lines | ||
| 12 | 12 | AVCODECOBJS-$(CONFIG_IDCTDSP) += idctdsp.o |
| 13 | 13 | AVCODECOBJS-$(CONFIG_LLVIDDSP) += llviddsp.o |
| 14 | 14 | AVCODECOBJS-$(CONFIG_LLVIDENCDSP) += llviddspenc.o |
| 15 | +AVCODECOBJS-$(CONFIG_ME_CMP) += motion.o | |
| 15 | 16 | AVCODECOBJS-$(CONFIG_VC1DSP) += vc1dsp.o |
| 16 | 17 | AVCODECOBJS-$(CONFIG_VP8DSP) += vp8dsp.o |
| 17 | 18 | AVCODECOBJS-$(CONFIG_VIDEODSP) += videodsp.o |
| @@ -135,6 +135,9 @@ static const struct { · 134 unmodified lines | ||
| 135 | 135 | #if CONFIG_LLVIDENCDSP |
| 136 | 136 | { "llviddspenc", checkasm_check_llviddspenc }, |
| 137 | 137 | #endif |
| 138 | + #if CONFIG_ME_CMP | |
| 139 | + { "motion", checkasm_check_motion }, | |
| 140 | + #endif | |
| 138 | 141 | #if CONFIG_OPUS_DECODER |
| 139 | 142 | { "opusdsp", checkasm_check_opusdsp }, |
| 140 | 143 | #endif |
| @@ -68,6 +68,7 @@ void checkasm_check_idctdsp(void); · 67 unmodified lines | ||
| 68 | 68 | void checkasm_check_jpeg2000dsp(void); |
| 69 | 69 | void checkasm_check_llviddsp(void); |
| 70 | 70 | void checkasm_check_llviddspenc(void); |
| 71 | +void checkasm_check_motion(void); | |
| 71 | 72 | void checkasm_check_nlmeans(void); |
| 72 | 73 | void checkasm_check_opusdsp(void); |
| 73 | 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 | 23 | fate-checkasm-jpeg2000dsp \ |
| 24 | 24 | fate-checkasm-llviddsp \ |
| 25 | 25 | fate-checkasm-llviddspenc \ |
| 26 | + fate-checkasm-motion \ | |
| 26 | 27 | fate-checkasm-opusdsp \ |
| 27 | 28 | fate-checkasm-pixblockdsp \ |
| 28 | 29 | fate-checkasm-sbrdsp \ |