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