Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 1 | /* |
Yaowu Xu | 2ab7ff0 | 2016-09-02 12:04:54 -0700 | [diff] [blame] | 2 | * Copyright (c) 2016, Alliance for Open Media. All rights reserved |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 3 | * |
Yaowu Xu | 2ab7ff0 | 2016-09-02 12:04:54 -0700 | [diff] [blame] | 4 | * This source code is subject to the terms of the BSD 2 Clause License and |
| 5 | * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
| 6 | * was not distributed with this source code in the LICENSE file, you can |
| 7 | * obtain it at www.aomedia.org/license/software. If the Alliance for Open |
| 8 | * Media Patent License 1.0 was not distributed with this source code in the |
| 9 | * PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 10 | */ |
| 11 | |
| 12 | #include <arm_neon.h> |
| 13 | #include <assert.h> |
| 14 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 15 | #include "./aom_config.h" |
| 16 | #include "./aom_dsp_rtcd.h" |
| 17 | #include "aom/aom_integer.h" |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 18 | #include "aom_ports/mem.h" |
| 19 | |
| 20 | static INLINE int32x4_t MULTIPLY_BY_Q0(int16x4_t dsrc0, int16x4_t dsrc1, |
| 21 | int16x4_t dsrc2, int16x4_t dsrc3, |
| 22 | int16x4_t dsrc4, int16x4_t dsrc5, |
| 23 | int16x4_t dsrc6, int16x4_t dsrc7, |
| 24 | int16x8_t q0s16) { |
| 25 | int32x4_t qdst; |
| 26 | int16x4_t d0s16, d1s16; |
| 27 | |
| 28 | d0s16 = vget_low_s16(q0s16); |
| 29 | d1s16 = vget_high_s16(q0s16); |
| 30 | |
| 31 | qdst = vmull_lane_s16(dsrc0, d0s16, 0); |
| 32 | qdst = vmlal_lane_s16(qdst, dsrc1, d0s16, 1); |
| 33 | qdst = vmlal_lane_s16(qdst, dsrc2, d0s16, 2); |
| 34 | qdst = vmlal_lane_s16(qdst, dsrc3, d0s16, 3); |
| 35 | qdst = vmlal_lane_s16(qdst, dsrc4, d1s16, 0); |
| 36 | qdst = vmlal_lane_s16(qdst, dsrc5, d1s16, 1); |
| 37 | qdst = vmlal_lane_s16(qdst, dsrc6, d1s16, 2); |
| 38 | qdst = vmlal_lane_s16(qdst, dsrc7, d1s16, 3); |
| 39 | return qdst; |
| 40 | } |
| 41 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 42 | void aom_convolve8_horiz_neon(const uint8_t *src, ptrdiff_t src_stride, |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 43 | uint8_t *dst, ptrdiff_t dst_stride, |
| 44 | const int16_t *filter_x, int x_step_q4, |
| 45 | const int16_t *filter_y, // unused |
| 46 | int y_step_q4, // unused |
| 47 | int w, int h) { |
| 48 | int width; |
| 49 | const uint8_t *s, *psrc; |
| 50 | uint8_t *d, *pdst; |
| 51 | uint8x8_t d2u8, d3u8, d24u8, d25u8, d26u8, d27u8, d28u8, d29u8; |
| 52 | uint32x2_t d2u32, d3u32, d28u32, d29u32, d30u32, d31u32; |
| 53 | uint8x16_t q12u8, q13u8, q14u8, q15u8; |
| 54 | int16x4_t d16s16, d17s16, d18s16, d19s16, d20s16, d22s16, d23s16; |
| 55 | int16x4_t d24s16, d25s16, d26s16, d27s16; |
| 56 | uint16x4_t d2u16, d3u16, d4u16, d5u16, d16u16, d17u16, d18u16, d19u16; |
| 57 | int16x8_t q0s16; |
| 58 | uint16x8_t q1u16, q2u16, q8u16, q9u16, q10u16, q11u16, q12u16, q13u16; |
| 59 | int32x4_t q1s32, q2s32, q14s32, q15s32; |
| 60 | uint16x8x2_t q0x2u16; |
| 61 | uint8x8x2_t d0x2u8, d1x2u8; |
| 62 | uint32x2x2_t d0x2u32; |
| 63 | uint16x4x2_t d0x2u16, d1x2u16; |
| 64 | uint32x4x2_t q0x2u32; |
| 65 | |
| 66 | assert(x_step_q4 == 16); |
| 67 | |
Urvang Joshi | d71a231 | 2016-07-14 12:33:48 -0700 | [diff] [blame] | 68 | (void)x_step_q4; |
| 69 | (void)y_step_q4; |
| 70 | (void)filter_y; |
| 71 | |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 72 | q0s16 = vld1q_s16(filter_x); |
| 73 | |
| 74 | src -= 3; // adjust for taps |
| 75 | for (; h > 0; h -= 4, src += src_stride * 4, |
| 76 | dst += dst_stride * 4) { // loop_horiz_v |
| 77 | s = src; |
| 78 | d24u8 = vld1_u8(s); |
| 79 | s += src_stride; |
| 80 | d25u8 = vld1_u8(s); |
| 81 | s += src_stride; |
| 82 | d26u8 = vld1_u8(s); |
| 83 | s += src_stride; |
| 84 | d27u8 = vld1_u8(s); |
| 85 | |
| 86 | q12u8 = vcombine_u8(d24u8, d25u8); |
| 87 | q13u8 = vcombine_u8(d26u8, d27u8); |
| 88 | |
| 89 | q0x2u16 = |
| 90 | vtrnq_u16(vreinterpretq_u16_u8(q12u8), vreinterpretq_u16_u8(q13u8)); |
| 91 | d24u8 = vreinterpret_u8_u16(vget_low_u16(q0x2u16.val[0])); |
| 92 | d25u8 = vreinterpret_u8_u16(vget_high_u16(q0x2u16.val[0])); |
| 93 | d26u8 = vreinterpret_u8_u16(vget_low_u16(q0x2u16.val[1])); |
| 94 | d27u8 = vreinterpret_u8_u16(vget_high_u16(q0x2u16.val[1])); |
| 95 | d0x2u8 = vtrn_u8(d24u8, d25u8); |
| 96 | d1x2u8 = vtrn_u8(d26u8, d27u8); |
| 97 | |
| 98 | __builtin_prefetch(src + src_stride * 4); |
| 99 | __builtin_prefetch(src + src_stride * 5); |
| 100 | __builtin_prefetch(src + src_stride * 6); |
| 101 | |
| 102 | q8u16 = vmovl_u8(d0x2u8.val[0]); |
| 103 | q9u16 = vmovl_u8(d0x2u8.val[1]); |
| 104 | q10u16 = vmovl_u8(d1x2u8.val[0]); |
| 105 | q11u16 = vmovl_u8(d1x2u8.val[1]); |
| 106 | |
| 107 | d16u16 = vget_low_u16(q8u16); |
| 108 | d17u16 = vget_high_u16(q8u16); |
| 109 | d18u16 = vget_low_u16(q9u16); |
| 110 | d19u16 = vget_high_u16(q9u16); |
| 111 | q8u16 = vcombine_u16(d16u16, d18u16); // vswp 17 18 |
| 112 | q9u16 = vcombine_u16(d17u16, d19u16); |
| 113 | |
| 114 | d20s16 = vreinterpret_s16_u16(vget_low_u16(q10u16)); |
| 115 | d23s16 = vreinterpret_s16_u16(vget_high_u16(q10u16)); // vmov 23 21 |
| 116 | for (width = w, psrc = src + 7, pdst = dst; width > 0; |
| 117 | width -= 4, psrc += 4, pdst += 4) { // loop_horiz |
| 118 | s = psrc; |
| 119 | d28u32 = vld1_dup_u32((const uint32_t *)s); |
| 120 | s += src_stride; |
| 121 | d29u32 = vld1_dup_u32((const uint32_t *)s); |
| 122 | s += src_stride; |
| 123 | d31u32 = vld1_dup_u32((const uint32_t *)s); |
| 124 | s += src_stride; |
| 125 | d30u32 = vld1_dup_u32((const uint32_t *)s); |
| 126 | |
| 127 | __builtin_prefetch(psrc + 64); |
| 128 | |
| 129 | d0x2u16 = |
| 130 | vtrn_u16(vreinterpret_u16_u32(d28u32), vreinterpret_u16_u32(d31u32)); |
| 131 | d1x2u16 = |
| 132 | vtrn_u16(vreinterpret_u16_u32(d29u32), vreinterpret_u16_u32(d30u32)); |
| 133 | d0x2u8 = vtrn_u8(vreinterpret_u8_u16(d0x2u16.val[0]), // d28 |
| 134 | vreinterpret_u8_u16(d1x2u16.val[0])); // d29 |
| 135 | d1x2u8 = vtrn_u8(vreinterpret_u8_u16(d0x2u16.val[1]), // d31 |
| 136 | vreinterpret_u8_u16(d1x2u16.val[1])); // d30 |
| 137 | |
| 138 | __builtin_prefetch(psrc + 64 + src_stride); |
| 139 | |
| 140 | q14u8 = vcombine_u8(d0x2u8.val[0], d0x2u8.val[1]); |
| 141 | q15u8 = vcombine_u8(d1x2u8.val[1], d1x2u8.val[0]); |
| 142 | q0x2u32 = |
| 143 | vtrnq_u32(vreinterpretq_u32_u8(q14u8), vreinterpretq_u32_u8(q15u8)); |
| 144 | |
| 145 | d28u8 = vreinterpret_u8_u32(vget_low_u32(q0x2u32.val[0])); |
| 146 | d29u8 = vreinterpret_u8_u32(vget_high_u32(q0x2u32.val[0])); |
| 147 | q12u16 = vmovl_u8(d28u8); |
| 148 | q13u16 = vmovl_u8(d29u8); |
| 149 | |
| 150 | __builtin_prefetch(psrc + 64 + src_stride * 2); |
| 151 | |
| 152 | d16s16 = vreinterpret_s16_u16(vget_low_u16(q8u16)); |
| 153 | d17s16 = vreinterpret_s16_u16(vget_high_u16(q8u16)); |
| 154 | d18s16 = vreinterpret_s16_u16(vget_low_u16(q9u16)); |
| 155 | d19s16 = vreinterpret_s16_u16(vget_high_u16(q9u16)); |
| 156 | d22s16 = vreinterpret_s16_u16(vget_low_u16(q11u16)); |
| 157 | d24s16 = vreinterpret_s16_u16(vget_low_u16(q12u16)); |
| 158 | d25s16 = vreinterpret_s16_u16(vget_high_u16(q12u16)); |
| 159 | d26s16 = vreinterpret_s16_u16(vget_low_u16(q13u16)); |
| 160 | d27s16 = vreinterpret_s16_u16(vget_high_u16(q13u16)); |
| 161 | |
| 162 | q1s32 = MULTIPLY_BY_Q0(d16s16, d17s16, d20s16, d22s16, d18s16, d19s16, |
| 163 | d23s16, d24s16, q0s16); |
| 164 | q2s32 = MULTIPLY_BY_Q0(d17s16, d20s16, d22s16, d18s16, d19s16, d23s16, |
| 165 | d24s16, d26s16, q0s16); |
| 166 | q14s32 = MULTIPLY_BY_Q0(d20s16, d22s16, d18s16, d19s16, d23s16, d24s16, |
| 167 | d26s16, d27s16, q0s16); |
| 168 | q15s32 = MULTIPLY_BY_Q0(d22s16, d18s16, d19s16, d23s16, d24s16, d26s16, |
| 169 | d27s16, d25s16, q0s16); |
| 170 | |
| 171 | __builtin_prefetch(psrc + 60 + src_stride * 3); |
| 172 | |
| 173 | d2u16 = vqrshrun_n_s32(q1s32, 7); |
| 174 | d3u16 = vqrshrun_n_s32(q2s32, 7); |
| 175 | d4u16 = vqrshrun_n_s32(q14s32, 7); |
| 176 | d5u16 = vqrshrun_n_s32(q15s32, 7); |
| 177 | |
| 178 | q1u16 = vcombine_u16(d2u16, d3u16); |
| 179 | q2u16 = vcombine_u16(d4u16, d5u16); |
| 180 | |
| 181 | d2u8 = vqmovn_u16(q1u16); |
| 182 | d3u8 = vqmovn_u16(q2u16); |
| 183 | |
| 184 | d0x2u16 = vtrn_u16(vreinterpret_u16_u8(d2u8), vreinterpret_u16_u8(d3u8)); |
| 185 | d0x2u32 = vtrn_u32(vreinterpret_u32_u16(d0x2u16.val[0]), |
| 186 | vreinterpret_u32_u16(d0x2u16.val[1])); |
| 187 | d0x2u8 = vtrn_u8(vreinterpret_u8_u32(d0x2u32.val[0]), |
| 188 | vreinterpret_u8_u32(d0x2u32.val[1])); |
| 189 | |
| 190 | d2u32 = vreinterpret_u32_u8(d0x2u8.val[0]); |
| 191 | d3u32 = vreinterpret_u32_u8(d0x2u8.val[1]); |
| 192 | |
| 193 | d = pdst; |
| 194 | vst1_lane_u32((uint32_t *)d, d2u32, 0); |
| 195 | d += dst_stride; |
| 196 | vst1_lane_u32((uint32_t *)d, d3u32, 0); |
| 197 | d += dst_stride; |
| 198 | vst1_lane_u32((uint32_t *)d, d2u32, 1); |
| 199 | d += dst_stride; |
| 200 | vst1_lane_u32((uint32_t *)d, d3u32, 1); |
| 201 | |
| 202 | q8u16 = q9u16; |
| 203 | d20s16 = d23s16; |
| 204 | q11u16 = q12u16; |
| 205 | q9u16 = q13u16; |
| 206 | d23s16 = vreinterpret_s16_u16(vget_high_u16(q11u16)); |
| 207 | } |
| 208 | } |
| 209 | return; |
| 210 | } |
| 211 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 212 | void aom_convolve8_vert_neon(const uint8_t *src, ptrdiff_t src_stride, |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 213 | uint8_t *dst, ptrdiff_t dst_stride, |
| 214 | const int16_t *filter_x, // unused |
| 215 | int x_step_q4, // unused |
| 216 | const int16_t *filter_y, int y_step_q4, int w, |
| 217 | int h) { |
| 218 | int height; |
| 219 | const uint8_t *s; |
| 220 | uint8_t *d; |
| 221 | uint32x2_t d2u32, d3u32; |
| 222 | uint32x2_t d16u32, d18u32, d20u32, d22u32, d24u32, d26u32; |
| 223 | int16x4_t d16s16, d17s16, d18s16, d19s16, d20s16, d21s16, d22s16; |
| 224 | int16x4_t d24s16, d25s16, d26s16, d27s16; |
| 225 | uint16x4_t d2u16, d3u16, d4u16, d5u16; |
| 226 | int16x8_t q0s16; |
| 227 | uint16x8_t q1u16, q2u16, q8u16, q9u16, q10u16, q11u16, q12u16, q13u16; |
| 228 | int32x4_t q1s32, q2s32, q14s32, q15s32; |
| 229 | |
| 230 | assert(y_step_q4 == 16); |
| 231 | |
Urvang Joshi | d71a231 | 2016-07-14 12:33:48 -0700 | [diff] [blame] | 232 | (void)x_step_q4; |
| 233 | (void)y_step_q4; |
| 234 | (void)filter_x; |
| 235 | |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 236 | src -= src_stride * 3; |
| 237 | q0s16 = vld1q_s16(filter_y); |
| 238 | for (; w > 0; w -= 4, src += 4, dst += 4) { // loop_vert_h |
| 239 | s = src; |
| 240 | d16u32 = vld1_lane_u32((const uint32_t *)s, d16u32, 0); |
| 241 | s += src_stride; |
| 242 | d16u32 = vld1_lane_u32((const uint32_t *)s, d16u32, 1); |
| 243 | s += src_stride; |
| 244 | d18u32 = vld1_lane_u32((const uint32_t *)s, d18u32, 0); |
| 245 | s += src_stride; |
| 246 | d18u32 = vld1_lane_u32((const uint32_t *)s, d18u32, 1); |
| 247 | s += src_stride; |
| 248 | d20u32 = vld1_lane_u32((const uint32_t *)s, d20u32, 0); |
| 249 | s += src_stride; |
| 250 | d20u32 = vld1_lane_u32((const uint32_t *)s, d20u32, 1); |
| 251 | s += src_stride; |
| 252 | d22u32 = vld1_lane_u32((const uint32_t *)s, d22u32, 0); |
| 253 | s += src_stride; |
| 254 | |
| 255 | q8u16 = vmovl_u8(vreinterpret_u8_u32(d16u32)); |
| 256 | q9u16 = vmovl_u8(vreinterpret_u8_u32(d18u32)); |
| 257 | q10u16 = vmovl_u8(vreinterpret_u8_u32(d20u32)); |
| 258 | q11u16 = vmovl_u8(vreinterpret_u8_u32(d22u32)); |
| 259 | |
| 260 | d18s16 = vreinterpret_s16_u16(vget_low_u16(q9u16)); |
| 261 | d19s16 = vreinterpret_s16_u16(vget_high_u16(q9u16)); |
| 262 | d22s16 = vreinterpret_s16_u16(vget_low_u16(q11u16)); |
| 263 | d = dst; |
| 264 | for (height = h; height > 0; height -= 4) { // loop_vert |
| 265 | d24u32 = vld1_lane_u32((const uint32_t *)s, d24u32, 0); |
| 266 | s += src_stride; |
| 267 | d26u32 = vld1_lane_u32((const uint32_t *)s, d26u32, 0); |
| 268 | s += src_stride; |
| 269 | d26u32 = vld1_lane_u32((const uint32_t *)s, d26u32, 1); |
| 270 | s += src_stride; |
| 271 | d24u32 = vld1_lane_u32((const uint32_t *)s, d24u32, 1); |
| 272 | s += src_stride; |
| 273 | |
| 274 | q12u16 = vmovl_u8(vreinterpret_u8_u32(d24u32)); |
| 275 | q13u16 = vmovl_u8(vreinterpret_u8_u32(d26u32)); |
| 276 | |
| 277 | d16s16 = vreinterpret_s16_u16(vget_low_u16(q8u16)); |
| 278 | d17s16 = vreinterpret_s16_u16(vget_high_u16(q8u16)); |
| 279 | d20s16 = vreinterpret_s16_u16(vget_low_u16(q10u16)); |
| 280 | d21s16 = vreinterpret_s16_u16(vget_high_u16(q10u16)); |
| 281 | d24s16 = vreinterpret_s16_u16(vget_low_u16(q12u16)); |
| 282 | d25s16 = vreinterpret_s16_u16(vget_high_u16(q12u16)); |
| 283 | d26s16 = vreinterpret_s16_u16(vget_low_u16(q13u16)); |
| 284 | d27s16 = vreinterpret_s16_u16(vget_high_u16(q13u16)); |
| 285 | |
| 286 | __builtin_prefetch(d); |
| 287 | __builtin_prefetch(d + dst_stride); |
| 288 | q1s32 = MULTIPLY_BY_Q0(d16s16, d17s16, d18s16, d19s16, d20s16, d21s16, |
| 289 | d22s16, d24s16, q0s16); |
| 290 | __builtin_prefetch(d + dst_stride * 2); |
| 291 | __builtin_prefetch(d + dst_stride * 3); |
| 292 | q2s32 = MULTIPLY_BY_Q0(d17s16, d18s16, d19s16, d20s16, d21s16, d22s16, |
| 293 | d24s16, d26s16, q0s16); |
| 294 | __builtin_prefetch(s); |
| 295 | __builtin_prefetch(s + src_stride); |
| 296 | q14s32 = MULTIPLY_BY_Q0(d18s16, d19s16, d20s16, d21s16, d22s16, d24s16, |
| 297 | d26s16, d27s16, q0s16); |
| 298 | __builtin_prefetch(s + src_stride * 2); |
| 299 | __builtin_prefetch(s + src_stride * 3); |
| 300 | q15s32 = MULTIPLY_BY_Q0(d19s16, d20s16, d21s16, d22s16, d24s16, d26s16, |
| 301 | d27s16, d25s16, q0s16); |
| 302 | |
| 303 | d2u16 = vqrshrun_n_s32(q1s32, 7); |
| 304 | d3u16 = vqrshrun_n_s32(q2s32, 7); |
| 305 | d4u16 = vqrshrun_n_s32(q14s32, 7); |
| 306 | d5u16 = vqrshrun_n_s32(q15s32, 7); |
| 307 | |
| 308 | q1u16 = vcombine_u16(d2u16, d3u16); |
| 309 | q2u16 = vcombine_u16(d4u16, d5u16); |
| 310 | |
| 311 | d2u32 = vreinterpret_u32_u8(vqmovn_u16(q1u16)); |
| 312 | d3u32 = vreinterpret_u32_u8(vqmovn_u16(q2u16)); |
| 313 | |
| 314 | vst1_lane_u32((uint32_t *)d, d2u32, 0); |
| 315 | d += dst_stride; |
| 316 | vst1_lane_u32((uint32_t *)d, d2u32, 1); |
| 317 | d += dst_stride; |
| 318 | vst1_lane_u32((uint32_t *)d, d3u32, 0); |
| 319 | d += dst_stride; |
| 320 | vst1_lane_u32((uint32_t *)d, d3u32, 1); |
| 321 | d += dst_stride; |
| 322 | |
| 323 | q8u16 = q10u16; |
| 324 | d18s16 = d22s16; |
| 325 | d19s16 = d24s16; |
| 326 | q10u16 = q13u16; |
| 327 | d22s16 = d25s16; |
| 328 | } |
| 329 | } |
| 330 | return; |
| 331 | } |