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