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