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