enc_neon.c revision 1e7bf8805bd030c19924a5306837ecd72c295751
1// Copyright 2012 Google Inc. All Rights Reserved. 2// 3// This code is licensed under the same terms as WebM: 4// Software License Agreement: http://www.webmproject.org/license/software/ 5// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ 6// ----------------------------------------------------------------------------- 7// 8// ARM NEON version of speed-critical encoding functions. 9// 10// adapted from libvpx (http://www.webmproject.org/code/) 11 12#include "./dsp.h" 13 14#if defined(__cplusplus) || defined(c_plusplus) 15extern "C" { 16#endif 17 18#if defined(WEBP_USE_NEON) 19 20#include "../enc/vp8enci.h" 21 22//------------------------------------------------------------------------------ 23// Transforms (Paragraph 14.4) 24 25// Inverse transform. 26// This code is pretty much the same as TransformOneNEON in the decoder, except 27// for subtraction to *ref. See the comments there for algorithmic explanations. 28static void ITransformOne(const uint8_t* ref, 29 const int16_t* in, uint8_t* dst) { 30 const int kBPS = BPS; 31 const int16_t kC1C2[] = { 20091, 17734, 0, 0 }; // kC1 / (kC2 >> 1) / 0 / 0 32 33 __asm__ volatile ( 34 "vld1.16 {q1, q2}, [%[in]] \n" 35 "vld1.16 {d0}, [%[kC1C2]] \n" 36 37 // d2: in[0] 38 // d3: in[8] 39 // d4: in[4] 40 // d5: in[12] 41 "vswp d3, d4 \n" 42 43 // q8 = {in[4], in[12]} * kC1 * 2 >> 16 44 // q9 = {in[4], in[12]} * kC2 >> 16 45 "vqdmulh.s16 q8, q2, d0[0] \n" 46 "vqdmulh.s16 q9, q2, d0[1] \n" 47 48 // d22 = a = in[0] + in[8] 49 // d23 = b = in[0] - in[8] 50 "vqadd.s16 d22, d2, d3 \n" 51 "vqsub.s16 d23, d2, d3 \n" 52 53 // q8 = in[4]/[12] * kC1 >> 16 54 "vshr.s16 q8, q8, #1 \n" 55 56 // Add {in[4], in[12]} back after the multiplication. 57 "vqadd.s16 q8, q2, q8 \n" 58 59 // d20 = c = in[4]*kC2 - in[12]*kC1 60 // d21 = d = in[4]*kC1 + in[12]*kC2 61 "vqsub.s16 d20, d18, d17 \n" 62 "vqadd.s16 d21, d19, d16 \n" 63 64 // d2 = tmp[0] = a + d 65 // d3 = tmp[1] = b + c 66 // d4 = tmp[2] = b - c 67 // d5 = tmp[3] = a - d 68 "vqadd.s16 d2, d22, d21 \n" 69 "vqadd.s16 d3, d23, d20 \n" 70 "vqsub.s16 d4, d23, d20 \n" 71 "vqsub.s16 d5, d22, d21 \n" 72 73 "vzip.16 q1, q2 \n" 74 "vzip.16 q1, q2 \n" 75 76 "vswp d3, d4 \n" 77 78 // q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16 79 // q9 = {tmp[4], tmp[12]} * kC2 >> 16 80 "vqdmulh.s16 q8, q2, d0[0] \n" 81 "vqdmulh.s16 q9, q2, d0[1] \n" 82 83 // d22 = a = tmp[0] + tmp[8] 84 // d23 = b = tmp[0] - tmp[8] 85 "vqadd.s16 d22, d2, d3 \n" 86 "vqsub.s16 d23, d2, d3 \n" 87 88 "vshr.s16 q8, q8, #1 \n" 89 "vqadd.s16 q8, q2, q8 \n" 90 91 // d20 = c = in[4]*kC2 - in[12]*kC1 92 // d21 = d = in[4]*kC1 + in[12]*kC2 93 "vqsub.s16 d20, d18, d17 \n" 94 "vqadd.s16 d21, d19, d16 \n" 95 96 // d2 = tmp[0] = a + d 97 // d3 = tmp[1] = b + c 98 // d4 = tmp[2] = b - c 99 // d5 = tmp[3] = a - d 100 "vqadd.s16 d2, d22, d21 \n" 101 "vqadd.s16 d3, d23, d20 \n" 102 "vqsub.s16 d4, d23, d20 \n" 103 "vqsub.s16 d5, d22, d21 \n" 104 105 "vld1.32 d6[0], [%[ref]], %[kBPS] \n" 106 "vld1.32 d6[1], [%[ref]], %[kBPS] \n" 107 "vld1.32 d7[0], [%[ref]], %[kBPS] \n" 108 "vld1.32 d7[1], [%[ref]], %[kBPS] \n" 109 110 "sub %[ref], %[ref], %[kBPS], lsl #2 \n" 111 112 // (val) + 4 >> 3 113 "vrshr.s16 d2, d2, #3 \n" 114 "vrshr.s16 d3, d3, #3 \n" 115 "vrshr.s16 d4, d4, #3 \n" 116 "vrshr.s16 d5, d5, #3 \n" 117 118 "vzip.16 q1, q2 \n" 119 "vzip.16 q1, q2 \n" 120 121 // Must accumulate before saturating 122 "vmovl.u8 q8, d6 \n" 123 "vmovl.u8 q9, d7 \n" 124 125 "vqadd.s16 q1, q1, q8 \n" 126 "vqadd.s16 q2, q2, q9 \n" 127 128 "vqmovun.s16 d0, q1 \n" 129 "vqmovun.s16 d1, q2 \n" 130 131 "vst1.32 d0[0], [%[dst]], %[kBPS] \n" 132 "vst1.32 d0[1], [%[dst]], %[kBPS] \n" 133 "vst1.32 d1[0], [%[dst]], %[kBPS] \n" 134 "vst1.32 d1[1], [%[dst]] \n" 135 136 : [in] "+r"(in), [dst] "+r"(dst) // modified registers 137 : [kBPS] "r"(kBPS), [kC1C2] "r"(kC1C2), [ref] "r"(ref) // constants 138 : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" // clobbered 139 ); 140} 141 142static void ITransform(const uint8_t* ref, 143 const int16_t* in, uint8_t* dst, int do_two) { 144 ITransformOne(ref, in, dst); 145 if (do_two) { 146 ITransformOne(ref + 4, in + 16, dst + 4); 147 } 148} 149 150// Same code as dec_neon.c 151static void ITransformWHT(const int16_t* in, int16_t* out) { 152 const int kStep = 32; // The store is only incrementing the pointer as if we 153 // had stored a single byte. 154 __asm__ volatile ( 155 // part 1 156 // load data into q0, q1 157 "vld1.16 {q0, q1}, [%[in]] \n" 158 159 "vaddl.s16 q2, d0, d3 \n" // a0 = in[0] + in[12] 160 "vaddl.s16 q3, d1, d2 \n" // a1 = in[4] + in[8] 161 "vsubl.s16 q4, d1, d2 \n" // a2 = in[4] - in[8] 162 "vsubl.s16 q5, d0, d3 \n" // a3 = in[0] - in[12] 163 164 "vadd.s32 q0, q2, q3 \n" // tmp[0] = a0 + a1 165 "vsub.s32 q2, q2, q3 \n" // tmp[8] = a0 - a1 166 "vadd.s32 q1, q5, q4 \n" // tmp[4] = a3 + a2 167 "vsub.s32 q3, q5, q4 \n" // tmp[12] = a3 - a2 168 169 // Transpose 170 // q0 = tmp[0, 4, 8, 12], q1 = tmp[2, 6, 10, 14] 171 // q2 = tmp[1, 5, 9, 13], q3 = tmp[3, 7, 11, 15] 172 "vswp d1, d4 \n" // vtrn.64 q0, q2 173 "vswp d3, d6 \n" // vtrn.64 q1, q3 174 "vtrn.32 q0, q1 \n" 175 "vtrn.32 q2, q3 \n" 176 177 "vmov.s32 q4, #3 \n" // dc = 3 178 "vadd.s32 q0, q0, q4 \n" // dc = tmp[0] + 3 179 "vadd.s32 q6, q0, q3 \n" // a0 = dc + tmp[3] 180 "vadd.s32 q7, q1, q2 \n" // a1 = tmp[1] + tmp[2] 181 "vsub.s32 q8, q1, q2 \n" // a2 = tmp[1] - tmp[2] 182 "vsub.s32 q9, q0, q3 \n" // a3 = dc - tmp[3] 183 184 "vadd.s32 q0, q6, q7 \n" 185 "vshrn.s32 d0, q0, #3 \n" // (a0 + a1) >> 3 186 "vadd.s32 q1, q9, q8 \n" 187 "vshrn.s32 d1, q1, #3 \n" // (a3 + a2) >> 3 188 "vsub.s32 q2, q6, q7 \n" 189 "vshrn.s32 d2, q2, #3 \n" // (a0 - a1) >> 3 190 "vsub.s32 q3, q9, q8 \n" 191 "vshrn.s32 d3, q3, #3 \n" // (a3 - a2) >> 3 192 193 // set the results to output 194 "vst1.16 d0[0], [%[out]], %[kStep] \n" 195 "vst1.16 d1[0], [%[out]], %[kStep] \n" 196 "vst1.16 d2[0], [%[out]], %[kStep] \n" 197 "vst1.16 d3[0], [%[out]], %[kStep] \n" 198 "vst1.16 d0[1], [%[out]], %[kStep] \n" 199 "vst1.16 d1[1], [%[out]], %[kStep] \n" 200 "vst1.16 d2[1], [%[out]], %[kStep] \n" 201 "vst1.16 d3[1], [%[out]], %[kStep] \n" 202 "vst1.16 d0[2], [%[out]], %[kStep] \n" 203 "vst1.16 d1[2], [%[out]], %[kStep] \n" 204 "vst1.16 d2[2], [%[out]], %[kStep] \n" 205 "vst1.16 d3[2], [%[out]], %[kStep] \n" 206 "vst1.16 d0[3], [%[out]], %[kStep] \n" 207 "vst1.16 d1[3], [%[out]], %[kStep] \n" 208 "vst1.16 d2[3], [%[out]], %[kStep] \n" 209 "vst1.16 d3[3], [%[out]], %[kStep] \n" 210 211 : [out] "+r"(out) // modified registers 212 : [in] "r"(in), [kStep] "r"(kStep) // constants 213 : "memory", "q0", "q1", "q2", "q3", "q4", 214 "q5", "q6", "q7", "q8", "q9" // clobbered 215 ); 216} 217 218// Forward transform. 219 220// adapted from vp8/encoder/arm/neon/shortfdct_neon.asm 221static const int16_t kCoeff16[] = { 222 5352, 5352, 5352, 5352, 2217, 2217, 2217, 2217 223}; 224static const int32_t kCoeff32[] = { 225 1812, 1812, 1812, 1812, 226 937, 937, 937, 937, 227 12000, 12000, 12000, 12000, 228 51000, 51000, 51000, 51000 229}; 230 231static void FTransform(const uint8_t* src, const uint8_t* ref, 232 int16_t* out) { 233 const int kBPS = BPS; 234 const uint8_t* src_ptr = src; 235 const uint8_t* ref_ptr = ref; 236 const int16_t* coeff16 = kCoeff16; 237 const int32_t* coeff32 = kCoeff32; 238 239 __asm__ volatile ( 240 // load src into q4, q5 in high half 241 "vld1.8 {d8}, [%[src_ptr]], %[kBPS] \n" 242 "vld1.8 {d10}, [%[src_ptr]], %[kBPS] \n" 243 "vld1.8 {d9}, [%[src_ptr]], %[kBPS] \n" 244 "vld1.8 {d11}, [%[src_ptr]] \n" 245 246 // load ref into q6, q7 in high half 247 "vld1.8 {d12}, [%[ref_ptr]], %[kBPS] \n" 248 "vld1.8 {d14}, [%[ref_ptr]], %[kBPS] \n" 249 "vld1.8 {d13}, [%[ref_ptr]], %[kBPS] \n" 250 "vld1.8 {d15}, [%[ref_ptr]] \n" 251 252 // Pack the high values in to q4 and q6 253 "vtrn.32 q4, q5 \n" 254 "vtrn.32 q6, q7 \n" 255 256 // d[0-3] = src - ref 257 "vsubl.u8 q0, d8, d12 \n" 258 "vsubl.u8 q1, d9, d13 \n" 259 260 // load coeff16 into q8(d16=5352, d17=2217) 261 "vld1.16 {q8}, [%[coeff16]] \n" 262 263 // load coeff32 high half into q9 = 1812, q10 = 937 264 "vld1.32 {q9, q10}, [%[coeff32]]! \n" 265 266 // load coeff32 low half into q11=12000, q12=51000 267 "vld1.32 {q11,q12}, [%[coeff32]] \n" 268 269 // part 1 270 // Transpose. Register dN is the same as dN in C 271 "vtrn.32 d0, d2 \n" 272 "vtrn.32 d1, d3 \n" 273 "vtrn.16 d0, d1 \n" 274 "vtrn.16 d2, d3 \n" 275 276 "vadd.s16 d4, d0, d3 \n" // a0 = d0 + d3 277 "vadd.s16 d5, d1, d2 \n" // a1 = d1 + d2 278 "vsub.s16 d6, d1, d2 \n" // a2 = d1 - d2 279 "vsub.s16 d7, d0, d3 \n" // a3 = d0 - d3 280 281 "vadd.s16 d0, d4, d5 \n" // a0 + a1 282 "vshl.s16 d0, d0, #3 \n" // temp[0+i*4] = (a0+a1) << 3 283 "vsub.s16 d2, d4, d5 \n" // a0 - a1 284 "vshl.s16 d2, d2, #3 \n" // (temp[2+i*4] = (a0-a1) << 3 285 286 "vmlal.s16 q9, d7, d16 \n" // a3*5352 + 1812 287 "vmlal.s16 q10, d7, d17 \n" // a3*2217 + 937 288 "vmlal.s16 q9, d6, d17 \n" // a2*2217 + a3*5352 + 1812 289 "vmlsl.s16 q10, d6, d16 \n" // a3*2217 + 937 - a2*5352 290 291 // temp[1+i*4] = (d2*2217 + d3*5352 + 1812) >> 9 292 // temp[3+i*4] = (d3*2217 + 937 - d2*5352) >> 9 293 "vshrn.s32 d1, q9, #9 \n" 294 "vshrn.s32 d3, q10, #9 \n" 295 296 // part 2 297 // transpose d0=ip[0], d1=ip[4], d2=ip[8], d3=ip[12] 298 "vtrn.32 d0, d2 \n" 299 "vtrn.32 d1, d3 \n" 300 "vtrn.16 d0, d1 \n" 301 "vtrn.16 d2, d3 \n" 302 303 "vmov.s16 d26, #7 \n" 304 305 "vadd.s16 d4, d0, d3 \n" // a1 = ip[0] + ip[12] 306 "vadd.s16 d5, d1, d2 \n" // b1 = ip[4] + ip[8] 307 "vsub.s16 d6, d1, d2 \n" // c1 = ip[4] - ip[8] 308 "vadd.s16 d4, d4, d26 \n" // a1 + 7 309 "vsub.s16 d7, d0, d3 \n" // d1 = ip[0] - ip[12] 310 311 "vadd.s16 d0, d4, d5 \n" // op[0] = a1 + b1 + 7 312 "vsub.s16 d2, d4, d5 \n" // op[8] = a1 - b1 + 7 313 314 "vmlal.s16 q11, d7, d16 \n" // d1*5352 + 12000 315 "vmlal.s16 q12, d7, d17 \n" // d1*2217 + 51000 316 317 "vceq.s16 d4, d7, #0 \n" 318 319 "vshr.s16 d0, d0, #4 \n" 320 "vshr.s16 d2, d2, #4 \n" 321 322 "vmlal.s16 q11, d6, d17 \n" // c1*2217 + d1*5352 + 12000 323 "vmlsl.s16 q12, d6, d16 \n" // d1*2217 - c1*5352 + 51000 324 325 "vmvn.s16 d4, d4 \n" 326 // op[4] = (c1*2217 + d1*5352 + 12000)>>16 327 "vshrn.s32 d1, q11, #16 \n" 328 // op[4] += (d1!=0) 329 "vsub.s16 d1, d1, d4 \n" 330 // op[12]= (d1*2217 - c1*5352 + 51000)>>16 331 "vshrn.s32 d3, q12, #16 \n" 332 333 // set result to out array 334 "vst1.16 {q0, q1}, [%[out]] \n" 335 : [src_ptr] "+r"(src_ptr), [ref_ptr] "+r"(ref_ptr), 336 [coeff32] "+r"(coeff32) // modified registers 337 : [kBPS] "r"(kBPS), [coeff16] "r"(coeff16), 338 [out] "r"(out) // constants 339 : "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", 340 "q10", "q11", "q12", "q13" // clobbered 341 ); 342} 343 344static void FTransformWHT(const int16_t* in, int16_t* out) { 345 const int kStep = 32; 346 __asm__ volatile ( 347 // d0 = in[0 * 16] , d1 = in[1 * 16] 348 // d2 = in[2 * 16] , d3 = in[3 * 16] 349 "vld1.16 d0[0], [%[in]], %[kStep] \n" 350 "vld1.16 d1[0], [%[in]], %[kStep] \n" 351 "vld1.16 d2[0], [%[in]], %[kStep] \n" 352 "vld1.16 d3[0], [%[in]], %[kStep] \n" 353 "vld1.16 d0[1], [%[in]], %[kStep] \n" 354 "vld1.16 d1[1], [%[in]], %[kStep] \n" 355 "vld1.16 d2[1], [%[in]], %[kStep] \n" 356 "vld1.16 d3[1], [%[in]], %[kStep] \n" 357 "vld1.16 d0[2], [%[in]], %[kStep] \n" 358 "vld1.16 d1[2], [%[in]], %[kStep] \n" 359 "vld1.16 d2[2], [%[in]], %[kStep] \n" 360 "vld1.16 d3[2], [%[in]], %[kStep] \n" 361 "vld1.16 d0[3], [%[in]], %[kStep] \n" 362 "vld1.16 d1[3], [%[in]], %[kStep] \n" 363 "vld1.16 d2[3], [%[in]], %[kStep] \n" 364 "vld1.16 d3[3], [%[in]], %[kStep] \n" 365 366 "vaddl.s16 q2, d0, d2 \n" 367 "vshl.s32 q2, q2, #2 \n" // a0=(in[0*16]+in[2*16])<<2 368 "vaddl.s16 q3, d1, d3 \n" 369 "vshl.s32 q3, q3, #2 \n" // a1=(in[1*16]+in[3*16])<<2 370 "vsubl.s16 q4, d1, d3 \n" 371 "vshl.s32 q4, q4, #2 \n" // a2=(in[1*16]-in[3*16])<<2 372 "vsubl.s16 q5, d0, d2 \n" 373 "vshl.s32 q5, q5, #2 \n" // a3=(in[0*16]-in[2*16])<<2 374 375 "vceq.s32 q10, q2, #0 \n" 376 "vmvn.s32 q10, q10 \n" // (a0 != 0) 377 "vqadd.s32 q6, q2, q3 \n" // (a0 + a1) 378 "vqsub.s32 q6, q6, q10 \n" // (a0 + a1) + (a0 != 0) 379 "vqadd.s32 q7, q5, q4 \n" // a3 + a2 380 "vqsub.s32 q8, q5, q4 \n" // a3 - a2 381 "vqsub.s32 q9, q2, q3 \n" // a0 - a1 382 383 // Transpose 384 // q6 = tmp[0, 1, 2, 3] ; q7 = tmp[ 4, 5, 6, 7] 385 // q8 = tmp[8, 9, 10, 11] ; q9 = tmp[12, 13, 14, 15] 386 "vswp d13, d16 \n" // vtrn.64 q0, q2 387 "vswp d15, d18 \n" // vtrn.64 q1, q3 388 "vtrn.32 q6, q7 \n" 389 "vtrn.32 q8, q9 \n" 390 391 "vqadd.s32 q0, q6, q8 \n" // a0 = tmp[0] + tmp[8] 392 "vqadd.s32 q1, q7, q9 \n" // a1 = tmp[4] + tmp[12] 393 "vqsub.s32 q2, q7, q9 \n" // a2 = tmp[4] - tmp[12] 394 "vqsub.s32 q3, q6, q8 \n" // a3 = tmp[0] - tmp[8] 395 396 "vqadd.s32 q4, q0, q1 \n" // b0 = a0 + a1 397 "vqadd.s32 q5, q3, q2 \n" // b1 = a3 + a2 398 "vqsub.s32 q6, q3, q2 \n" // b2 = a3 - a2 399 "vqsub.s32 q7, q0, q1 \n" // b3 = a0 - a1 400 401 "vmov.s32 q0, #3 \n" // q0 = 3 402 403 "vcgt.s32 q1, q4, #0 \n" // (b0>0) 404 "vqsub.s32 q2, q4, q1 \n" // (b0+(b0>0)) 405 "vqadd.s32 q3, q2, q0 \n" // (b0+(b0>0)+3) 406 "vshrn.s32 d18, q3, #3 \n" // (b0+(b0>0)+3) >> 3 407 408 "vcgt.s32 q1, q5, #0 \n" // (b1>0) 409 "vqsub.s32 q2, q5, q1 \n" // (b1+(b1>0)) 410 "vqadd.s32 q3, q2, q0 \n" // (b1+(b1>0)+3) 411 "vshrn.s32 d19, q3, #3 \n" // (b1+(b1>0)+3) >> 3 412 413 "vcgt.s32 q1, q6, #0 \n" // (b2>0) 414 "vqsub.s32 q2, q6, q1 \n" // (b2+(b2>0)) 415 "vqadd.s32 q3, q2, q0 \n" // (b2+(b2>0)+3) 416 "vshrn.s32 d20, q3, #3 \n" // (b2+(b2>0)+3) >> 3 417 418 "vcgt.s32 q1, q7, #0 \n" // (b3>0) 419 "vqsub.s32 q2, q7, q1 \n" // (b3+(b3>0)) 420 "vqadd.s32 q3, q2, q0 \n" // (b3+(b3>0)+3) 421 "vshrn.s32 d21, q3, #3 \n" // (b3+(b3>0)+3) >> 3 422 423 "vst1.16 {q9, q10}, [%[out]] \n" 424 425 : [in] "+r"(in) 426 : [kStep] "r"(kStep), [out] "r"(out) 427 : "memory", "q0", "q1", "q2", "q3", "q4", "q5", 428 "q6", "q7", "q8", "q9", "q10" // clobbered 429 ) ; 430} 431 432//------------------------------------------------------------------------------ 433// Texture distortion 434// 435// We try to match the spectral content (weighted) between source and 436// reconstructed samples. 437 438// Hadamard transform 439// Returns the weighted sum of the absolute value of transformed coefficients. 440// This uses a TTransform helper function in C 441static int Disto4x4(const uint8_t* const a, const uint8_t* const b, 442 const uint16_t* const w) { 443 const int kBPS = BPS; 444 const uint8_t* A = a; 445 const uint8_t* B = b; 446 const uint16_t* W = w; 447 int sum; 448 __asm__ volatile ( 449 "vld1.32 d0[0], [%[a]], %[kBPS] \n" 450 "vld1.32 d0[1], [%[a]], %[kBPS] \n" 451 "vld1.32 d2[0], [%[a]], %[kBPS] \n" 452 "vld1.32 d2[1], [%[a]] \n" 453 454 "vld1.32 d1[0], [%[b]], %[kBPS] \n" 455 "vld1.32 d1[1], [%[b]], %[kBPS] \n" 456 "vld1.32 d3[0], [%[b]], %[kBPS] \n" 457 "vld1.32 d3[1], [%[b]] \n" 458 459 // a d0/d2, b d1/d3 460 // d0/d1: 01 01 01 01 461 // d2/d3: 23 23 23 23 462 // But: it goes 01 45 23 67 463 // Notice the middle values are transposed 464 "vtrn.16 q0, q1 \n" 465 466 // {a0, a1} = {in[0] + in[2], in[1] + in[3]} 467 "vaddl.u8 q2, d0, d2 \n" 468 "vaddl.u8 q10, d1, d3 \n" 469 // {a3, a2} = {in[0] - in[2], in[1] - in[3]} 470 "vsubl.u8 q3, d0, d2 \n" 471 "vsubl.u8 q11, d1, d3 \n" 472 473 // tmp[0] = a0 + a1 474 "vpaddl.s16 q0, q2 \n" 475 "vpaddl.s16 q8, q10 \n" 476 477 // tmp[1] = a3 + a2 478 "vpaddl.s16 q1, q3 \n" 479 "vpaddl.s16 q9, q11 \n" 480 481 // No pair subtract 482 // q2 = {a0, a3} 483 // q3 = {a1, a2} 484 "vtrn.16 q2, q3 \n" 485 "vtrn.16 q10, q11 \n" 486 487 // {tmp[3], tmp[2]} = {a0 - a1, a3 - a2} 488 "vsubl.s16 q12, d4, d6 \n" 489 "vsubl.s16 q13, d5, d7 \n" 490 "vsubl.s16 q14, d20, d22 \n" 491 "vsubl.s16 q15, d21, d23 \n" 492 493 // separate tmp[3] and tmp[2] 494 // q12 = tmp[3] 495 // q13 = tmp[2] 496 "vtrn.32 q12, q13 \n" 497 "vtrn.32 q14, q15 \n" 498 499 // Transpose tmp for a 500 "vswp d1, d26 \n" // vtrn.64 501 "vswp d3, d24 \n" // vtrn.64 502 "vtrn.32 q0, q1 \n" 503 "vtrn.32 q13, q12 \n" 504 505 // Transpose tmp for b 506 "vswp d17, d30 \n" // vtrn.64 507 "vswp d19, d28 \n" // vtrn.64 508 "vtrn.32 q8, q9 \n" 509 "vtrn.32 q15, q14 \n" 510 511 // The first Q register is a, the second b. 512 // q0/8 tmp[0-3] 513 // q13/15 tmp[4-7] 514 // q1/9 tmp[8-11] 515 // q12/14 tmp[12-15] 516 517 // These are still in 01 45 23 67 order. We fix it easily in the addition 518 // case but the subtraction propegates them. 519 "vswp d3, d27 \n" 520 "vswp d19, d31 \n" 521 522 // a0 = tmp[0] + tmp[8] 523 "vadd.s32 q2, q0, q1 \n" 524 "vadd.s32 q3, q8, q9 \n" 525 526 // a1 = tmp[4] + tmp[12] 527 "vadd.s32 q10, q13, q12 \n" 528 "vadd.s32 q11, q15, q14 \n" 529 530 // a2 = tmp[4] - tmp[12] 531 "vsub.s32 q13, q13, q12 \n" 532 "vsub.s32 q15, q15, q14 \n" 533 534 // a3 = tmp[0] - tmp[8] 535 "vsub.s32 q0, q0, q1 \n" 536 "vsub.s32 q8, q8, q9 \n" 537 538 // b0 = a0 + a1 539 "vadd.s32 q1, q2, q10 \n" 540 "vadd.s32 q9, q3, q11 \n" 541 542 // b1 = a3 + a2 543 "vadd.s32 q12, q0, q13 \n" 544 "vadd.s32 q14, q8, q15 \n" 545 546 // b2 = a3 - a2 547 "vsub.s32 q0, q0, q13 \n" 548 "vsub.s32 q8, q8, q15 \n" 549 550 // b3 = a0 - a1 551 "vsub.s32 q2, q2, q10 \n" 552 "vsub.s32 q3, q3, q11 \n" 553 554 "vld1.64 {q10, q11}, [%[w]] \n" 555 556 // abs(b0) 557 "vabs.s32 q1, q1 \n" 558 "vabs.s32 q9, q9 \n" 559 // abs(b1) 560 "vabs.s32 q12, q12 \n" 561 "vabs.s32 q14, q14 \n" 562 // abs(b2) 563 "vabs.s32 q0, q0 \n" 564 "vabs.s32 q8, q8 \n" 565 // abs(b3) 566 "vabs.s32 q2, q2 \n" 567 "vabs.s32 q3, q3 \n" 568 569 // expand w before using. 570 "vmovl.u16 q13, d20 \n" 571 "vmovl.u16 q15, d21 \n" 572 573 // w[0] * abs(b0) 574 "vmul.u32 q1, q1, q13 \n" 575 "vmul.u32 q9, q9, q13 \n" 576 577 // w[4] * abs(b1) 578 "vmla.u32 q1, q12, q15 \n" 579 "vmla.u32 q9, q14, q15 \n" 580 581 // expand w before using. 582 "vmovl.u16 q13, d22 \n" 583 "vmovl.u16 q15, d23 \n" 584 585 // w[8] * abs(b1) 586 "vmla.u32 q1, q0, q13 \n" 587 "vmla.u32 q9, q8, q13 \n" 588 589 // w[12] * abs(b1) 590 "vmla.u32 q1, q2, q15 \n" 591 "vmla.u32 q9, q3, q15 \n" 592 593 // Sum the arrays 594 "vpaddl.u32 q1, q1 \n" 595 "vpaddl.u32 q9, q9 \n" 596 "vadd.u64 d2, d3 \n" 597 "vadd.u64 d18, d19 \n" 598 599 // Hadamard transform needs 4 bits of extra precision (2 bits in each 600 // direction) for dynamic raw. Weights w[] are 16bits at max, so the maximum 601 // precision for coeff is 8bit of input + 4bits of Hadamard transform + 602 // 16bits for w[] + 2 bits of abs() summation. 603 // 604 // This uses a maximum of 31 bits (signed). Discarding the top 32 bits is 605 // A-OK. 606 607 // sum2 - sum1 608 "vsub.u32 d0, d2, d18 \n" 609 // abs(sum2 - sum1) 610 "vabs.s32 d0, d0 \n" 611 // abs(sum2 - sum1) >> 5 612 "vshr.u32 d0, #5 \n" 613 614 // It would be better to move the value straight into r0 but I'm not 615 // entirely sure how this works with inline assembly. 616 "vmov.32 %[sum], d0[0] \n" 617 618 : [sum] "=r"(sum), [a] "+r"(A), [b] "+r"(B), [w] "+r"(W) 619 : [kBPS] "r"(kBPS) 620 : "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", 621 "q10", "q11", "q12", "q13", "q14", "q15" // clobbered 622 ) ; 623 624 return sum; 625} 626 627static int Disto16x16(const uint8_t* const a, const uint8_t* const b, 628 const uint16_t* const w) { 629 int D = 0; 630 int x, y; 631 for (y = 0; y < 16 * BPS; y += 4 * BPS) { 632 for (x = 0; x < 16; x += 4) { 633 D += Disto4x4(a + x + y, b + x + y, w); 634 } 635 } 636 return D; 637} 638 639#endif // WEBP_USE_NEON 640 641//------------------------------------------------------------------------------ 642// Entry point 643 644extern void VP8EncDspInitNEON(void); 645 646void VP8EncDspInitNEON(void) { 647#if defined(WEBP_USE_NEON) 648 VP8ITransform = ITransform; 649 VP8FTransform = FTransform; 650 651 VP8ITransformWHT = ITransformWHT; 652 VP8FTransformWHT = FTransformWHT; 653 654 VP8TDisto4x4 = Disto4x4; 655 VP8TDisto16x16 = Disto16x16; 656#endif // WEBP_USE_NEON 657} 658 659#if defined(__cplusplus) || defined(c_plusplus) 660} // extern "C" 661#endif 662