jsimd_arm_neon.S revision 82bd52196d0ee3eda47bfbb3da8fb886739484bf
1/* 2 * ARM NEON optimizations for libjpeg-turbo 3 * 4 * Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). 5 * All rights reserved. 6 * Contact: Alexander Bokovoy <alexander.bokovoy@nokia.com> 7 * 8 * This software is provided 'as-is', without any express or implied 9 * warranty. In no event will the authors be held liable for any damages 10 * arising from the use of this software. 11 * 12 * Permission is granted to anyone to use this software for any purpose, 13 * including commercial applications, and to alter it and redistribute it 14 * freely, subject to the following restrictions: 15 * 16 * 1. The origin of this software must not be misrepresented; you must not 17 * claim that you wrote the original software. If you use this software 18 * in a product, an acknowledgment in the product documentation would be 19 * appreciated but is not required. 20 * 2. Altered source versions must be plainly marked as such, and must not be 21 * misrepresented as being the original software. 22 * 3. This notice may not be removed or altered from any source distribution. 23 */ 24 25#if defined(__linux__) && defined(__ELF__) 26.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */ 27#endif 28 29.text 30.fpu neon 31.arch armv7a 32.object_arch armv4 33.arm 34 35 36#define RESPECT_STRICT_ALIGNMENT 1 37 38/*****************************************************************************/ 39 40/* Supplementary macro for setting function attributes */ 41.macro asm_function fname 42#ifdef __APPLE__ 43 .func _\fname 44 .globl _\fname 45_\fname: 46#else 47 .func \fname 48 .global \fname 49#ifdef __ELF__ 50 .hidden \fname 51 .type \fname, %function 52#endif 53\fname: 54#endif 55.endm 56 57/* Transpose a block of 4x4 coefficients in four 64-bit registers */ 58.macro transpose_4x4 x0, x1, x2, x3 59 vtrn.16 \x0, \x1 60 vtrn.16 \x2, \x3 61 vtrn.32 \x0, \x2 62 vtrn.32 \x1, \x3 63.endm 64 65/*****************************************************************************/ 66 67/* 68 * jsimd_idct_ifast_neon 69 * 70 * This function contains a fast, not so accurate integer implementation of 71 * the inverse DCT (Discrete Cosine Transform). It uses the same calculations 72 * and produces exactly the same output as IJG's original 'jpeg_idct_ifast' 73 * function from jidctfst.c 74 * 75 * Normally 1-D AAN DCT needs 5 multiplications and 29 additions. 76 * But in ARM NEON case some extra additions are required because VQDMULH 77 * instruction can't handle the constants larger than 1. So the expressions 78 * like "x * 1.082392200" have to be converted to "x * 0.082392200 + x", 79 * which introduces an extra addition. Overall, there are 6 extra additions 80 * per 1-D IDCT pass, totalling to 5 VQDMULH and 35 VADD/VSUB instructions. 81 */ 82 83#define XFIX_1_082392200 d0[0] 84#define XFIX_1_414213562 d0[1] 85#define XFIX_1_847759065 d0[2] 86#define XFIX_2_613125930 d0[3] 87 88.balign 16 89jsimd_idct_ifast_neon_consts: 90 .short (277 * 128 - 256 * 128) /* XFIX_1_082392200 */ 91 .short (362 * 128 - 256 * 128) /* XFIX_1_414213562 */ 92 .short (473 * 128 - 256 * 128) /* XFIX_1_847759065 */ 93 .short (669 * 128 - 512 * 128) /* XFIX_2_613125930 */ 94 95asm_function jsimd_idct_ifast_neon 96 97 DCT_TABLE .req r0 98 COEF_BLOCK .req r1 99 OUTPUT_BUF .req r2 100 OUTPUT_COL .req r3 101 TMP1 .req r0 102 TMP2 .req r1 103 TMP3 .req r2 104 TMP4 .req ip 105 106 /* Load and dequantize coefficients into NEON registers 107 * with the following allocation: 108 * 0 1 2 3 | 4 5 6 7 109 * ---------+-------- 110 * 0 | d16 | d17 ( q8 ) 111 * 1 | d18 | d19 ( q9 ) 112 * 2 | d20 | d21 ( q10 ) 113 * 3 | d22 | d23 ( q11 ) 114 * 4 | d24 | d25 ( q12 ) 115 * 5 | d26 | d27 ( q13 ) 116 * 6 | d28 | d29 ( q14 ) 117 * 7 | d30 | d31 ( q15 ) 118 */ 119 adr ip, jsimd_idct_ifast_neon_consts 120 vld1.16 {d16, d17, d18, d19}, [COEF_BLOCK, :128]! 121 vld1.16 {d0, d1, d2, d3}, [DCT_TABLE, :128]! 122 vld1.16 {d20, d21, d22, d23}, [COEF_BLOCK, :128]! 123 vmul.s16 q8, q8, q0 124 vld1.16 {d4, d5, d6, d7}, [DCT_TABLE, :128]! 125 vmul.s16 q9, q9, q1 126 vld1.16 {d24, d25, d26, d27}, [COEF_BLOCK, :128]! 127 vmul.s16 q10, q10, q2 128 vld1.16 {d0, d1, d2, d3}, [DCT_TABLE, :128]! 129 vmul.s16 q11, q11, q3 130 vld1.16 {d28, d29, d30, d31}, [COEF_BLOCK, :128] 131 vmul.s16 q12, q12, q0 132 vld1.16 {d4, d5, d6, d7}, [DCT_TABLE, :128]! 133 vmul.s16 q14, q14, q2 134 vmul.s16 q13, q13, q1 135 vld1.16 {d0}, [ip, :64] /* load constants */ 136 vmul.s16 q15, q15, q3 137 vpush {d8-d13} /* save NEON registers */ 138 /* 1-D IDCT, pass 1 */ 139 vsub.s16 q2, q10, q14 140 vadd.s16 q14, q10, q14 141 vsub.s16 q1, q11, q13 142 vadd.s16 q13, q11, q13 143 vsub.s16 q5, q9, q15 144 vadd.s16 q15, q9, q15 145 vqdmulh.s16 q4, q2, XFIX_1_414213562 146 vqdmulh.s16 q6, q1, XFIX_2_613125930 147 vadd.s16 q3, q1, q1 148 vsub.s16 q1, q5, q1 149 vadd.s16 q10, q2, q4 150 vqdmulh.s16 q4, q1, XFIX_1_847759065 151 vsub.s16 q2, q15, q13 152 vadd.s16 q3, q3, q6 153 vqdmulh.s16 q6, q2, XFIX_1_414213562 154 vadd.s16 q1, q1, q4 155 vqdmulh.s16 q4, q5, XFIX_1_082392200 156 vsub.s16 q10, q10, q14 157 vadd.s16 q2, q2, q6 158 vsub.s16 q6, q8, q12 159 vadd.s16 q12, q8, q12 160 vadd.s16 q9, q5, q4 161 vadd.s16 q5, q6, q10 162 vsub.s16 q10, q6, q10 163 vadd.s16 q6, q15, q13 164 vadd.s16 q8, q12, q14 165 vsub.s16 q3, q6, q3 166 vsub.s16 q12, q12, q14 167 vsub.s16 q3, q3, q1 168 vsub.s16 q1, q9, q1 169 vadd.s16 q2, q3, q2 170 vsub.s16 q15, q8, q6 171 vadd.s16 q1, q1, q2 172 vadd.s16 q8, q8, q6 173 vadd.s16 q14, q5, q3 174 vsub.s16 q9, q5, q3 175 vsub.s16 q13, q10, q2 176 vadd.s16 q10, q10, q2 177 /* Transpose */ 178 vtrn.16 q8, q9 179 vsub.s16 q11, q12, q1 180 vtrn.16 q14, q15 181 vadd.s16 q12, q12, q1 182 vtrn.16 q10, q11 183 vtrn.16 q12, q13 184 vtrn.32 q9, q11 185 vtrn.32 q12, q14 186 vtrn.32 q8, q10 187 vtrn.32 q13, q15 188 vswp d28, d21 189 vswp d26, d19 190 /* 1-D IDCT, pass 2 */ 191 vsub.s16 q2, q10, q14 192 vswp d30, d23 193 vadd.s16 q14, q10, q14 194 vswp d24, d17 195 vsub.s16 q1, q11, q13 196 vadd.s16 q13, q11, q13 197 vsub.s16 q5, q9, q15 198 vadd.s16 q15, q9, q15 199 vqdmulh.s16 q4, q2, XFIX_1_414213562 200 vqdmulh.s16 q6, q1, XFIX_2_613125930 201 vadd.s16 q3, q1, q1 202 vsub.s16 q1, q5, q1 203 vadd.s16 q10, q2, q4 204 vqdmulh.s16 q4, q1, XFIX_1_847759065 205 vsub.s16 q2, q15, q13 206 vadd.s16 q3, q3, q6 207 vqdmulh.s16 q6, q2, XFIX_1_414213562 208 vadd.s16 q1, q1, q4 209 vqdmulh.s16 q4, q5, XFIX_1_082392200 210 vsub.s16 q10, q10, q14 211 vadd.s16 q2, q2, q6 212 vsub.s16 q6, q8, q12 213 vadd.s16 q12, q8, q12 214 vadd.s16 q9, q5, q4 215 vadd.s16 q5, q6, q10 216 vsub.s16 q10, q6, q10 217 vadd.s16 q6, q15, q13 218 vadd.s16 q8, q12, q14 219 vsub.s16 q3, q6, q3 220 vsub.s16 q12, q12, q14 221 vsub.s16 q3, q3, q1 222 vsub.s16 q1, q9, q1 223 vadd.s16 q2, q3, q2 224 vsub.s16 q15, q8, q6 225 vadd.s16 q1, q1, q2 226 vadd.s16 q8, q8, q6 227 vadd.s16 q14, q5, q3 228 vsub.s16 q9, q5, q3 229 vsub.s16 q13, q10, q2 230 vpop {d8-d13} /* restore NEON registers */ 231 vadd.s16 q10, q10, q2 232 /* Transpose */ 233 vtrn.16 q8, q9 234 vsub.s16 q11, q12, q1 235 vtrn.16 q14, q15 236 vadd.s16 q12, q12, q1 237 vtrn.16 q10, q11 238 vtrn.16 q12, q13 239 /* Descale and range limit */ 240 vmov.s16 q0, #(0x80 << 5) 241 vtrn.32 q9, q11 242 vtrn.32 q12, q14 243 vtrn.32 q8, q10 244 vtrn.32 q13, q15 245 vswp d24, d17 246 vswp d26, d19 247 vqadd.s16 q8, q8, q0 248 vswp d28, d21 249 vqadd.s16 q9, q9, q0 250 vswp d30, d23 251 vqadd.s16 q10, q10, q0 252 vqadd.s16 q11, q11, q0 253 /* Store results to the output buffer */ 254 ldmia OUTPUT_BUF!, {TMP1, TMP2} 255 add TMP1, TMP1, OUTPUT_COL 256 add TMP2, TMP2, OUTPUT_COL 257 vqshrun.s16 d16, q8, #5 258 vqshrun.s16 d17, q9, #5 259 vqshrun.s16 d18, q10, #5 260 vqshrun.s16 d19, q11, #5 261 vst1.8 {d16}, [TMP1] 262 vqadd.s16 q12, q12, q0 263 vqadd.s16 q13, q13, q0 264 vst1.8 {d17}, [TMP2] 265 vqadd.s16 q14, q14, q0 266 vqadd.s16 q15, q15, q0 267 ldmia OUTPUT_BUF!, {TMP1, TMP2} 268 add TMP1, TMP1, OUTPUT_COL 269 add TMP2, TMP2, OUTPUT_COL 270 vst1.8 {d18}, [TMP1] 271 vqshrun.s16 d20, q12, #5 272 vqshrun.s16 d21, q13, #5 273 vst1.8 {d19}, [TMP2] 274 vqshrun.s16 d22, q14, #5 275 ldmia OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4} 276 add TMP1, TMP1, OUTPUT_COL 277 add TMP2, TMP2, OUTPUT_COL 278 add TMP3, TMP3, OUTPUT_COL 279 add TMP4, TMP4, OUTPUT_COL 280 vst1.8 {d20}, [TMP1] 281 vqshrun.s16 d23, q15, #5 282 vst1.8 {d21}, [TMP2] 283 vst1.8 {d22}, [TMP3] 284 vst1.8 {d23}, [TMP4] 285 bx lr 286 287 .unreq DCT_TABLE 288 .unreq COEF_BLOCK 289 .unreq OUTPUT_BUF 290 .unreq OUTPUT_COL 291 .unreq TMP1 292 .unreq TMP2 293 .unreq TMP3 294 .unreq TMP4 295.endfunc 296 297/*****************************************************************************/ 298 299/* 300 * jsimd_idct_4x4_neon 301 * 302 * This function contains inverse-DCT code for getting reduced-size 303 * 4x4 pixels output from an 8x8 DCT block. It uses the same calculations 304 * and produces exactly the same output as IJG's original 'jpeg_idct_4x4' 305 * function from jpeg-6b (jidctred.c). 306 * 307 * NOTE: jpeg-8 has an improved implementation of 4x4 inverse-DCT, which 308 * requires much less arithmetic operations and hence should be faster. 309 * The primary purpose of this particular NEON optimized function is 310 * bit exact compatibility with jpeg-6b. 311 * 312 * TODO: a bit better instructions scheduling can be achieved by expanding 313 * idct_helper/transpose_4x4 macros and reordering instructions, 314 * but readability will suffer somewhat. 315 */ 316 317#define CONST_BITS 13 318 319#define FIX_0_211164243 (1730) /* FIX(0.211164243) */ 320#define FIX_0_509795579 (4176) /* FIX(0.509795579) */ 321#define FIX_0_601344887 (4926) /* FIX(0.601344887) */ 322#define FIX_0_720959822 (5906) /* FIX(0.720959822) */ 323#define FIX_0_765366865 (6270) /* FIX(0.765366865) */ 324#define FIX_0_850430095 (6967) /* FIX(0.850430095) */ 325#define FIX_0_899976223 (7373) /* FIX(0.899976223) */ 326#define FIX_1_061594337 (8697) /* FIX(1.061594337) */ 327#define FIX_1_272758580 (10426) /* FIX(1.272758580) */ 328#define FIX_1_451774981 (11893) /* FIX(1.451774981) */ 329#define FIX_1_847759065 (15137) /* FIX(1.847759065) */ 330#define FIX_2_172734803 (17799) /* FIX(2.172734803) */ 331#define FIX_2_562915447 (20995) /* FIX(2.562915447) */ 332#define FIX_3_624509785 (29692) /* FIX(3.624509785) */ 333 334.balign 16 335jsimd_idct_4x4_neon_consts: 336 .short FIX_1_847759065 /* d0[0] */ 337 .short -FIX_0_765366865 /* d0[1] */ 338 .short -FIX_0_211164243 /* d0[2] */ 339 .short FIX_1_451774981 /* d0[3] */ 340 .short -FIX_2_172734803 /* d1[0] */ 341 .short FIX_1_061594337 /* d1[1] */ 342 .short -FIX_0_509795579 /* d1[2] */ 343 .short -FIX_0_601344887 /* d1[3] */ 344 .short FIX_0_899976223 /* d2[0] */ 345 .short FIX_2_562915447 /* d2[1] */ 346 .short 1 << (CONST_BITS+1) /* d2[2] */ 347 .short 0 /* d2[3] */ 348 349.macro idct_helper x4, x6, x8, x10, x12, x14, x16, shift, y26, y27, y28, y29 350 vmull.s16 q14, \x4, d2[2] 351 vmlal.s16 q14, \x8, d0[0] 352 vmlal.s16 q14, \x14, d0[1] 353 354 vmull.s16 q13, \x16, d1[2] 355 vmlal.s16 q13, \x12, d1[3] 356 vmlal.s16 q13, \x10, d2[0] 357 vmlal.s16 q13, \x6, d2[1] 358 359 vmull.s16 q15, \x4, d2[2] 360 vmlsl.s16 q15, \x8, d0[0] 361 vmlsl.s16 q15, \x14, d0[1] 362 363 vmull.s16 q12, \x16, d0[2] 364 vmlal.s16 q12, \x12, d0[3] 365 vmlal.s16 q12, \x10, d1[0] 366 vmlal.s16 q12, \x6, d1[1] 367 368 vadd.s32 q10, q14, q13 369 vsub.s32 q14, q14, q13 370 371.if \shift > 16 372 vrshr.s32 q10, q10, #\shift 373 vrshr.s32 q14, q14, #\shift 374 vmovn.s32 \y26, q10 375 vmovn.s32 \y29, q14 376.else 377 vrshrn.s32 \y26, q10, #\shift 378 vrshrn.s32 \y29, q14, #\shift 379.endif 380 381 vadd.s32 q10, q15, q12 382 vsub.s32 q15, q15, q12 383 384.if \shift > 16 385 vrshr.s32 q10, q10, #\shift 386 vrshr.s32 q15, q15, #\shift 387 vmovn.s32 \y27, q10 388 vmovn.s32 \y28, q15 389.else 390 vrshrn.s32 \y27, q10, #\shift 391 vrshrn.s32 \y28, q15, #\shift 392.endif 393 394.endm 395 396asm_function jsimd_idct_4x4_neon 397 398 DCT_TABLE .req r0 399 COEF_BLOCK .req r1 400 OUTPUT_BUF .req r2 401 OUTPUT_COL .req r3 402 TMP1 .req r0 403 TMP2 .req r1 404 TMP3 .req r2 405 TMP4 .req ip 406 407 vpush {d8-d15} 408 409 /* Load constants (d3 is just used for padding) */ 410 adr TMP4, jsimd_idct_4x4_neon_consts 411 vld1.16 {d0, d1, d2, d3}, [TMP4, :128] 412 413 /* Load all COEF_BLOCK into NEON registers with the following allocation: 414 * 0 1 2 3 | 4 5 6 7 415 * ---------+-------- 416 * 0 | d4 | d5 417 * 1 | d6 | d7 418 * 2 | d8 | d9 419 * 3 | d10 | d11 420 * 4 | - | - 421 * 5 | d12 | d13 422 * 6 | d14 | d15 423 * 7 | d16 | d17 424 */ 425 vld1.16 {d4, d5, d6, d7}, [COEF_BLOCK, :128]! 426 vld1.16 {d8, d9, d10, d11}, [COEF_BLOCK, :128]! 427 add COEF_BLOCK, COEF_BLOCK, #16 428 vld1.16 {d12, d13, d14, d15}, [COEF_BLOCK, :128]! 429 vld1.16 {d16, d17}, [COEF_BLOCK, :128]! 430 /* dequantize */ 431 vld1.16 {d18, d19, d20, d21}, [DCT_TABLE, :128]! 432 vmul.s16 q2, q2, q9 433 vld1.16 {d22, d23, d24, d25}, [DCT_TABLE, :128]! 434 vmul.s16 q3, q3, q10 435 vmul.s16 q4, q4, q11 436 add DCT_TABLE, DCT_TABLE, #16 437 vld1.16 {d26, d27, d28, d29}, [DCT_TABLE, :128]! 438 vmul.s16 q5, q5, q12 439 vmul.s16 q6, q6, q13 440 vld1.16 {d30, d31}, [DCT_TABLE, :128]! 441 vmul.s16 q7, q7, q14 442 vmul.s16 q8, q8, q15 443 444 /* Pass 1 */ 445 idct_helper d4, d6, d8, d10, d12, d14, d16, 12, d4, d6, d8, d10 446 transpose_4x4 d4, d6, d8, d10 447 idct_helper d5, d7, d9, d11, d13, d15, d17, 12, d5, d7, d9, d11 448 transpose_4x4 d5, d7, d9, d11 449 450 /* Pass 2 */ 451 idct_helper d4, d6, d8, d10, d7, d9, d11, 19, d26, d27, d28, d29 452 transpose_4x4 d26, d27, d28, d29 453 454 /* Range limit */ 455 vmov.u16 q15, #0x80 456 vadd.s16 q13, q13, q15 457 vadd.s16 q14, q14, q15 458 vqmovun.s16 d26, q13 459 vqmovun.s16 d27, q14 460 461 /* Store results to the output buffer */ 462 ldmia OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4} 463 add TMP1, TMP1, OUTPUT_COL 464 add TMP2, TMP2, OUTPUT_COL 465 add TMP3, TMP3, OUTPUT_COL 466 add TMP4, TMP4, OUTPUT_COL 467 468#if defined(__ARMEL__) && !RESPECT_STRICT_ALIGNMENT 469 /* We can use much less instructions on little endian systems if the 470 * OS kernel is not configured to trap unaligned memory accesses 471 */ 472 vst1.32 {d26[0]}, [TMP1]! 473 vst1.32 {d27[0]}, [TMP3]! 474 vst1.32 {d26[1]}, [TMP2]! 475 vst1.32 {d27[1]}, [TMP4]! 476#else 477 vst1.8 {d26[0]}, [TMP1]! 478 vst1.8 {d27[0]}, [TMP3]! 479 vst1.8 {d26[1]}, [TMP1]! 480 vst1.8 {d27[1]}, [TMP3]! 481 vst1.8 {d26[2]}, [TMP1]! 482 vst1.8 {d27[2]}, [TMP3]! 483 vst1.8 {d26[3]}, [TMP1]! 484 vst1.8 {d27[3]}, [TMP3]! 485 486 vst1.8 {d26[4]}, [TMP2]! 487 vst1.8 {d27[4]}, [TMP4]! 488 vst1.8 {d26[5]}, [TMP2]! 489 vst1.8 {d27[5]}, [TMP4]! 490 vst1.8 {d26[6]}, [TMP2]! 491 vst1.8 {d27[6]}, [TMP4]! 492 vst1.8 {d26[7]}, [TMP2]! 493 vst1.8 {d27[7]}, [TMP4]! 494#endif 495 496 vpop {d8-d15} 497 bx lr 498 499 .unreq DCT_TABLE 500 .unreq COEF_BLOCK 501 .unreq OUTPUT_BUF 502 .unreq OUTPUT_COL 503 .unreq TMP1 504 .unreq TMP2 505 .unreq TMP3 506 .unreq TMP4 507.endfunc 508 509.purgem idct_helper 510 511/*****************************************************************************/ 512 513/* 514 * jsimd_idct_2x2_neon 515 * 516 * This function contains inverse-DCT code for getting reduced-size 517 * 2x2 pixels output from an 8x8 DCT block. It uses the same calculations 518 * and produces exactly the same output as IJG's original 'jpeg_idct_2x2' 519 * function from jpeg-6b (jidctred.c). 520 * 521 * NOTE: jpeg-8 has an improved implementation of 2x2 inverse-DCT, which 522 * requires much less arithmetic operations and hence should be faster. 523 * The primary purpose of this particular NEON optimized function is 524 * bit exact compatibility with jpeg-6b. 525 */ 526 527.balign 8 528jsimd_idct_2x2_neon_consts: 529 .short -FIX_0_720959822 /* d0[0] */ 530 .short FIX_0_850430095 /* d0[1] */ 531 .short -FIX_1_272758580 /* d0[2] */ 532 .short FIX_3_624509785 /* d0[3] */ 533 534.macro idct_helper x4, x6, x10, x12, x16, shift, y26, y27 535 vshll.s16 q14, \x4, #15 536 vmull.s16 q13, \x6, d0[3] 537 vmlal.s16 q13, \x10, d0[2] 538 vmlal.s16 q13, \x12, d0[1] 539 vmlal.s16 q13, \x16, d0[0] 540 541 vadd.s32 q10, q14, q13 542 vsub.s32 q14, q14, q13 543 544.if \shift > 16 545 vrshr.s32 q10, q10, #\shift 546 vrshr.s32 q14, q14, #\shift 547 vmovn.s32 \y26, q10 548 vmovn.s32 \y27, q14 549.else 550 vrshrn.s32 \y26, q10, #\shift 551 vrshrn.s32 \y27, q14, #\shift 552.endif 553 554.endm 555 556asm_function jsimd_idct_2x2_neon 557 558 DCT_TABLE .req r0 559 COEF_BLOCK .req r1 560 OUTPUT_BUF .req r2 561 OUTPUT_COL .req r3 562 TMP1 .req r0 563 TMP2 .req ip 564 565 vpush {d8-d15} 566 567 /* Load constants */ 568 adr TMP2, jsimd_idct_2x2_neon_consts 569 vld1.16 {d0}, [TMP2, :64] 570 571 /* Load all COEF_BLOCK into NEON registers with the following allocation: 572 * 0 1 2 3 | 4 5 6 7 573 * ---------+-------- 574 * 0 | d4 | d5 575 * 1 | d6 | d7 576 * 2 | - | - 577 * 3 | d10 | d11 578 * 4 | - | - 579 * 5 | d12 | d13 580 * 6 | - | - 581 * 7 | d16 | d17 582 */ 583 vld1.16 {d4, d5, d6, d7}, [COEF_BLOCK, :128]! 584 add COEF_BLOCK, COEF_BLOCK, #16 585 vld1.16 {d10, d11}, [COEF_BLOCK, :128]! 586 add COEF_BLOCK, COEF_BLOCK, #16 587 vld1.16 {d12, d13}, [COEF_BLOCK, :128]! 588 add COEF_BLOCK, COEF_BLOCK, #16 589 vld1.16 {d16, d17}, [COEF_BLOCK, :128]! 590 /* Dequantize */ 591 vld1.16 {d18, d19, d20, d21}, [DCT_TABLE, :128]! 592 vmul.s16 q2, q2, q9 593 vmul.s16 q3, q3, q10 594 add DCT_TABLE, DCT_TABLE, #16 595 vld1.16 {d24, d25}, [DCT_TABLE, :128]! 596 vmul.s16 q5, q5, q12 597 add DCT_TABLE, DCT_TABLE, #16 598 vld1.16 {d26, d27}, [DCT_TABLE, :128]! 599 vmul.s16 q6, q6, q13 600 add DCT_TABLE, DCT_TABLE, #16 601 vld1.16 {d30, d31}, [DCT_TABLE, :128]! 602 vmul.s16 q8, q8, q15 603 604 /* Pass 1 */ 605#if 0 606 idct_helper d4, d6, d10, d12, d16, 13, d4, d6 607 transpose_4x4 d4, d6, d8, d10 608 idct_helper d5, d7, d11, d13, d17, 13, d5, d7 609 transpose_4x4 d5, d7, d9, d11 610#else 611 vmull.s16 q13, d6, d0[3] 612 vmlal.s16 q13, d10, d0[2] 613 vmlal.s16 q13, d12, d0[1] 614 vmlal.s16 q13, d16, d0[0] 615 vmull.s16 q12, d7, d0[3] 616 vmlal.s16 q12, d11, d0[2] 617 vmlal.s16 q12, d13, d0[1] 618 vmlal.s16 q12, d17, d0[0] 619 vshll.s16 q14, d4, #15 620 vshll.s16 q15, d5, #15 621 vadd.s32 q10, q14, q13 622 vsub.s32 q14, q14, q13 623 vrshrn.s32 d4, q10, #13 624 vrshrn.s32 d6, q14, #13 625 vadd.s32 q10, q15, q12 626 vsub.s32 q14, q15, q12 627 vrshrn.s32 d5, q10, #13 628 vrshrn.s32 d7, q14, #13 629 vtrn.16 q2, q3 630 vtrn.32 q3, q5 631#endif 632 633 /* Pass 2 */ 634 idct_helper d4, d6, d10, d7, d11, 20, d26, d27 635 636 /* Range limit */ 637 vmov.u16 q15, #0x80 638 vadd.s16 q13, q13, q15 639 vqmovun.s16 d26, q13 640 vqmovun.s16 d27, q13 641 642 /* Store results to the output buffer */ 643 ldmia OUTPUT_BUF, {TMP1, TMP2} 644 add TMP1, TMP1, OUTPUT_COL 645 add TMP2, TMP2, OUTPUT_COL 646 647 vst1.8 {d26[0]}, [TMP1]! 648 vst1.8 {d27[4]}, [TMP1]! 649 vst1.8 {d26[1]}, [TMP2]! 650 vst1.8 {d27[5]}, [TMP2]! 651 652 vpop {d8-d15} 653 bx lr 654 655 .unreq DCT_TABLE 656 .unreq COEF_BLOCK 657 .unreq OUTPUT_BUF 658 .unreq OUTPUT_COL 659 .unreq TMP1 660 .unreq TMP2 661.endfunc 662 663.purgem idct_helper 664 665/*****************************************************************************/ 666 667/* 668 * jsimd_ycc_extrgb_convert_neon 669 * jsimd_ycc_extbgr_convert_neon 670 * jsimd_ycc_extrgbx_convert_neon 671 * jsimd_ycc_extbgrx_convert_neon 672 * jsimd_ycc_extxbgr_convert_neon 673 * jsimd_ycc_extxrgb_convert_neon 674 * 675 * Colorspace conversion YCbCr -> RGB 676 */ 677 678 679.macro do_load size 680 .if \size == 8 681 vld1.8 {d4}, [U]! 682 vld1.8 {d5}, [V]! 683 vld1.8 {d0}, [Y]! 684 pld [Y, #64] 685 pld [U, #64] 686 pld [V, #64] 687 .elseif \size == 4 688 vld1.8 {d4[0]}, [U]! 689 vld1.8 {d4[1]}, [U]! 690 vld1.8 {d4[2]}, [U]! 691 vld1.8 {d4[3]}, [U]! 692 vld1.8 {d5[0]}, [V]! 693 vld1.8 {d5[1]}, [V]! 694 vld1.8 {d5[2]}, [V]! 695 vld1.8 {d5[3]}, [V]! 696 vld1.8 {d0[0]}, [Y]! 697 vld1.8 {d0[1]}, [Y]! 698 vld1.8 {d0[2]}, [Y]! 699 vld1.8 {d0[3]}, [Y]! 700 .elseif \size == 2 701 vld1.8 {d4[4]}, [U]! 702 vld1.8 {d4[5]}, [U]! 703 vld1.8 {d5[4]}, [V]! 704 vld1.8 {d5[5]}, [V]! 705 vld1.8 {d0[4]}, [Y]! 706 vld1.8 {d0[5]}, [Y]! 707 .elseif \size == 1 708 vld1.8 {d4[6]}, [U]! 709 vld1.8 {d5[6]}, [V]! 710 vld1.8 {d0[6]}, [Y]! 711 .else 712 .error unsupported macroblock size 713 .endif 714.endm 715 716.macro do_store bpp, size 717 .if \bpp == 24 718 .if \size == 8 719 vst3.8 {d10, d11, d12}, [RGB]! 720 .elseif \size == 4 721 vst3.8 {d10[0], d11[0], d12[0]}, [RGB]! 722 vst3.8 {d10[1], d11[1], d12[1]}, [RGB]! 723 vst3.8 {d10[2], d11[2], d12[2]}, [RGB]! 724 vst3.8 {d10[3], d11[3], d12[3]}, [RGB]! 725 .elseif \size == 2 726 vst3.8 {d10[4], d11[4], d12[4]}, [RGB]! 727 vst3.8 {d10[5], d11[5], d12[5]}, [RGB]! 728 .elseif \size == 1 729 vst3.8 {d10[6], d11[6], d12[6]}, [RGB]! 730 .else 731 .error unsupported macroblock size 732 .endif 733 .elseif \bpp == 32 734 .if \size == 8 735 vst4.8 {d10, d11, d12, d13}, [RGB]! 736 .elseif \size == 4 737 vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [RGB]! 738 vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [RGB]! 739 vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [RGB]! 740 vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [RGB]! 741 .elseif \size == 2 742 vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [RGB]! 743 vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [RGB]! 744 .elseif \size == 1 745 vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [RGB]! 746 .else 747 .error unsupported macroblock size 748 .endif 749 .else 750 .error unsupported bpp 751 .endif 752.endm 753 754.macro generate_jsimd_ycc_rgb_convert_neon colorid, bpp, r_offs, g_offs, b_offs 755 756.macro do_yuv_to_rgb 757 vaddw.u8 q3, q1, d4 /* q3 = u - 128 */ 758 vaddw.u8 q4, q1, d5 /* q2 = v - 128 */ 759 vmull.s16 q10, d6, d1[1] /* multiply by -11277 */ 760 vmlal.s16 q10, d8, d1[2] /* multiply by -23401 */ 761 vmull.s16 q11, d7, d1[1] /* multiply by -11277 */ 762 vmlal.s16 q11, d9, d1[2] /* multiply by -23401 */ 763 vmull.s16 q12, d8, d1[0] /* multiply by 22971 */ 764 vmull.s16 q13, d9, d1[0] /* multiply by 22971 */ 765 vmull.s16 q14, d6, d1[3] /* multiply by 29033 */ 766 vmull.s16 q15, d7, d1[3] /* multiply by 29033 */ 767 vrshrn.s32 d20, q10, #15 768 vrshrn.s32 d21, q11, #15 769 vrshrn.s32 d24, q12, #14 770 vrshrn.s32 d25, q13, #14 771 vrshrn.s32 d28, q14, #14 772 vrshrn.s32 d29, q15, #14 773 vaddw.u8 q10, q10, d0 774 vaddw.u8 q12, q12, d0 775 vaddw.u8 q14, q14, d0 776 vqmovun.s16 d1\g_offs, q10 777 vqmovun.s16 d1\r_offs, q12 778 vqmovun.s16 d1\b_offs, q14 779.endm 780 781/* Apple gas crashes on adrl, work around that by using adr. 782 * But this requires a copy of these constants for each function. 783 */ 784 785.balign 16 786jsimd_ycc_\colorid\()_neon_consts: 787 .short 0, 0, 0, 0 788 .short 22971, -11277, -23401, 29033 789 .short -128, -128, -128, -128 790 .short -128, -128, -128, -128 791 792asm_function jsimd_ycc_\colorid\()_convert_neon 793 OUTPUT_WIDTH .req r0 794 INPUT_BUF .req r1 795 INPUT_ROW .req r2 796 OUTPUT_BUF .req r3 797 NUM_ROWS .req r4 798 799 INPUT_BUF0 .req r5 800 INPUT_BUF1 .req r6 801 INPUT_BUF2 .req INPUT_BUF 802 803 RGB .req r7 804 Y .req r8 805 U .req r9 806 V .req r10 807 N .req ip 808 809 /* Load constants to d1, d2, d3 (d0 is just used for padding) */ 810 adr ip, jsimd_ycc_\colorid\()_neon_consts 811 vld1.16 {d0, d1, d2, d3}, [ip, :128] 812 813 /* Save ARM registers and handle input arguments */ 814 push {r4, r5, r6, r7, r8, r9, r10, lr} 815 ldr NUM_ROWS, [sp, #(4 * 8)] 816 ldr INPUT_BUF0, [INPUT_BUF] 817 ldr INPUT_BUF1, [INPUT_BUF, #4] 818 ldr INPUT_BUF2, [INPUT_BUF, #8] 819 .unreq INPUT_BUF 820 821 /* Save NEON registers */ 822 vpush {d8-d15} 823 824 /* Initially set d10, d11, d12, d13 to 0xFF */ 825 vmov.u8 q5, #255 826 vmov.u8 q6, #255 827 828 /* Outer loop over scanlines */ 829 cmp NUM_ROWS, #1 830 blt 9f 8310: 832 ldr Y, [INPUT_BUF0, INPUT_ROW, lsl #2] 833 ldr U, [INPUT_BUF1, INPUT_ROW, lsl #2] 834 mov N, OUTPUT_WIDTH 835 ldr V, [INPUT_BUF2, INPUT_ROW, lsl #2] 836 add INPUT_ROW, INPUT_ROW, #1 837 ldr RGB, [OUTPUT_BUF], #4 838 839 /* Inner loop over pixels */ 840 subs N, N, #8 841 blt 2f 8421: 843 do_load 8 844 do_yuv_to_rgb 845 do_store \bpp, 8 846 subs N, N, #8 847 bge 1b 848 tst N, #7 849 beq 8f 8502: 851 tst N, #4 852 beq 3f 853 do_load 4 8543: 855 tst N, #2 856 beq 4f 857 do_load 2 8584: 859 tst N, #1 860 beq 5f 861 do_load 1 8625: 863 do_yuv_to_rgb 864 tst N, #4 865 beq 6f 866 do_store \bpp, 4 8676: 868 tst N, #2 869 beq 7f 870 do_store \bpp, 2 8717: 872 tst N, #1 873 beq 8f 874 do_store \bpp, 1 8758: 876 subs NUM_ROWS, NUM_ROWS, #1 877 bgt 0b 8789: 879 /* Restore all registers and return */ 880 vpop {d8-d15} 881 pop {r4, r5, r6, r7, r8, r9, r10, pc} 882 883 .unreq OUTPUT_WIDTH 884 .unreq INPUT_ROW 885 .unreq OUTPUT_BUF 886 .unreq NUM_ROWS 887 .unreq INPUT_BUF0 888 .unreq INPUT_BUF1 889 .unreq INPUT_BUF2 890 .unreq RGB 891 .unreq Y 892 .unreq U 893 .unreq V 894 .unreq N 895.endfunc 896 897.purgem do_yuv_to_rgb 898 899.endm 900 901/*--------------------------------- id ----- bpp R G B */ 902generate_jsimd_ycc_rgb_convert_neon extrgb, 24, 0, 1, 2 903generate_jsimd_ycc_rgb_convert_neon extbgr, 24, 2, 1, 0 904generate_jsimd_ycc_rgb_convert_neon extrgbx, 32, 0, 1, 2 905generate_jsimd_ycc_rgb_convert_neon extbgrx, 32, 2, 1, 0 906generate_jsimd_ycc_rgb_convert_neon extxbgr, 32, 3, 2, 1 907generate_jsimd_ycc_rgb_convert_neon extxrgb, 32, 1, 2, 3 908 909.purgem do_load 910.purgem do_store 911 912/*****************************************************************************/ 913 914/* 915 * jsimd_extrgb_ycc_convert_neon 916 * jsimd_extbgr_ycc_convert_neon 917 * jsimd_extrgbx_ycc_convert_neon 918 * jsimd_extbgrx_ycc_convert_neon 919 * jsimd_extxbgr_ycc_convert_neon 920 * jsimd_extxrgb_ycc_convert_neon 921 * 922 * Colorspace conversion RGB -> YCbCr 923 */ 924 925.macro do_store size 926 .if \size == 8 927 vst1.8 {d20}, [Y]! 928 vst1.8 {d21}, [U]! 929 vst1.8 {d22}, [V]! 930 .elseif \size == 4 931 vst1.8 {d20[0]}, [Y]! 932 vst1.8 {d20[1]}, [Y]! 933 vst1.8 {d20[2]}, [Y]! 934 vst1.8 {d20[3]}, [Y]! 935 vst1.8 {d21[0]}, [U]! 936 vst1.8 {d21[1]}, [U]! 937 vst1.8 {d21[2]}, [U]! 938 vst1.8 {d21[3]}, [U]! 939 vst1.8 {d22[0]}, [V]! 940 vst1.8 {d22[1]}, [V]! 941 vst1.8 {d22[2]}, [V]! 942 vst1.8 {d22[3]}, [V]! 943 .elseif \size == 2 944 vst1.8 {d20[4]}, [Y]! 945 vst1.8 {d20[5]}, [Y]! 946 vst1.8 {d21[4]}, [U]! 947 vst1.8 {d21[5]}, [U]! 948 vst1.8 {d22[4]}, [V]! 949 vst1.8 {d22[5]}, [V]! 950 .elseif \size == 1 951 vst1.8 {d20[6]}, [Y]! 952 vst1.8 {d21[6]}, [U]! 953 vst1.8 {d22[6]}, [V]! 954 .else 955 .error unsupported macroblock size 956 .endif 957.endm 958 959.macro do_load bpp, size 960 .if \bpp == 24 961 .if \size == 8 962 vld3.8 {d10, d11, d12}, [RGB]! 963 pld [RGB, #128] 964 .elseif \size == 4 965 vld3.8 {d10[0], d11[0], d12[0]}, [RGB]! 966 vld3.8 {d10[1], d11[1], d12[1]}, [RGB]! 967 vld3.8 {d10[2], d11[2], d12[2]}, [RGB]! 968 vld3.8 {d10[3], d11[3], d12[3]}, [RGB]! 969 .elseif \size == 2 970 vld3.8 {d10[4], d11[4], d12[4]}, [RGB]! 971 vld3.8 {d10[5], d11[5], d12[5]}, [RGB]! 972 .elseif \size == 1 973 vld3.8 {d10[6], d11[6], d12[6]}, [RGB]! 974 .else 975 .error unsupported macroblock size 976 .endif 977 .elseif \bpp == 32 978 .if \size == 8 979 vld4.8 {d10, d11, d12, d13}, [RGB]! 980 pld [RGB, #128] 981 .elseif \size == 4 982 vld4.8 {d10[0], d11[0], d12[0], d13[0]}, [RGB]! 983 vld4.8 {d10[1], d11[1], d12[1], d13[1]}, [RGB]! 984 vld4.8 {d10[2], d11[2], d12[2], d13[2]}, [RGB]! 985 vld4.8 {d10[3], d11[3], d12[3], d13[3]}, [RGB]! 986 .elseif \size == 2 987 vld4.8 {d10[4], d11[4], d12[4], d13[4]}, [RGB]! 988 vld4.8 {d10[5], d11[5], d12[5], d13[5]}, [RGB]! 989 .elseif \size == 1 990 vld4.8 {d10[6], d11[6], d12[6], d13[6]}, [RGB]! 991 .else 992 .error unsupported macroblock size 993 .endif 994 .else 995 .error unsupported bpp 996 .endif 997.endm 998 999.macro generate_jsimd_rgb_ycc_convert_neon colorid, bpp, r_offs, g_offs, b_offs 1000 1001/* 1002 * 2 stage pipelined RGB->YCbCr conversion 1003 */ 1004 1005.macro do_rgb_to_yuv_stage1 1006 vmovl.u8 q2, d1\r_offs /* r = { d4, d5 } */ 1007 vmovl.u8 q3, d1\g_offs /* g = { d6, d7 } */ 1008 vmovl.u8 q4, d1\b_offs /* b = { d8, d9 } */ 1009 vmull.u16 q7, d4, d0[0] 1010 vmlal.u16 q7, d6, d0[1] 1011 vmlal.u16 q7, d8, d0[2] 1012 vmull.u16 q8, d5, d0[0] 1013 vmlal.u16 q8, d7, d0[1] 1014 vmlal.u16 q8, d9, d0[2] 1015 vrev64.32 q9, q1 1016 vrev64.32 q13, q1 1017 vmlsl.u16 q9, d4, d0[3] 1018 vmlsl.u16 q9, d6, d1[0] 1019 vmlal.u16 q9, d8, d1[1] 1020 vmlsl.u16 q13, d5, d0[3] 1021 vmlsl.u16 q13, d7, d1[0] 1022 vmlal.u16 q13, d9, d1[1] 1023 vrev64.32 q14, q1 1024 vrev64.32 q15, q1 1025 vmlal.u16 q14, d4, d1[1] 1026 vmlsl.u16 q14, d6, d1[2] 1027 vmlsl.u16 q14, d8, d1[3] 1028 vmlal.u16 q15, d5, d1[1] 1029 vmlsl.u16 q15, d7, d1[2] 1030 vmlsl.u16 q15, d9, d1[3] 1031.endm 1032 1033.macro do_rgb_to_yuv_stage2 1034 vrshrn.u32 d20, q7, #16 1035 vrshrn.u32 d21, q8, #16 1036 vshrn.u32 d22, q9, #16 1037 vshrn.u32 d23, q13, #16 1038 vshrn.u32 d24, q14, #16 1039 vshrn.u32 d25, q15, #16 1040 vmovn.u16 d20, q10 /* d20 = y */ 1041 vmovn.u16 d21, q11 /* d21 = u */ 1042 vmovn.u16 d22, q12 /* d22 = v */ 1043.endm 1044 1045.macro do_rgb_to_yuv 1046 do_rgb_to_yuv_stage1 1047 do_rgb_to_yuv_stage2 1048.endm 1049 1050.macro do_rgb_to_yuv_stage2_store_load_stage1 1051 vrshrn.u32 d20, q7, #16 1052 vrshrn.u32 d21, q8, #16 1053 vshrn.u32 d22, q9, #16 1054 vrev64.32 q9, q1 1055 vshrn.u32 d23, q13, #16 1056 vrev64.32 q13, q1 1057 vshrn.u32 d24, q14, #16 1058 vshrn.u32 d25, q15, #16 1059 do_load \bpp, 8 1060 vmovn.u16 d20, q10 /* d20 = y */ 1061 vmovl.u8 q2, d1\r_offs /* r = { d4, d5 } */ 1062 vmovn.u16 d21, q11 /* d21 = u */ 1063 vmovl.u8 q3, d1\g_offs /* g = { d6, d7 } */ 1064 vmovn.u16 d22, q12 /* d22 = v */ 1065 vmovl.u8 q4, d1\b_offs /* b = { d8, d9 } */ 1066 vmull.u16 q7, d4, d0[0] 1067 vmlal.u16 q7, d6, d0[1] 1068 vmlal.u16 q7, d8, d0[2] 1069 vst1.8 {d20}, [Y]! 1070 vmull.u16 q8, d5, d0[0] 1071 vmlal.u16 q8, d7, d0[1] 1072 vmlal.u16 q8, d9, d0[2] 1073 vmlsl.u16 q9, d4, d0[3] 1074 vmlsl.u16 q9, d6, d1[0] 1075 vmlal.u16 q9, d8, d1[1] 1076 vst1.8 {d21}, [U]! 1077 vmlsl.u16 q13, d5, d0[3] 1078 vmlsl.u16 q13, d7, d1[0] 1079 vmlal.u16 q13, d9, d1[1] 1080 vrev64.32 q14, q1 1081 vrev64.32 q15, q1 1082 vmlal.u16 q14, d4, d1[1] 1083 vmlsl.u16 q14, d6, d1[2] 1084 vmlsl.u16 q14, d8, d1[3] 1085 vst1.8 {d22}, [V]! 1086 vmlal.u16 q15, d5, d1[1] 1087 vmlsl.u16 q15, d7, d1[2] 1088 vmlsl.u16 q15, d9, d1[3] 1089.endm 1090 1091.balign 16 1092jsimd_\colorid\()_ycc_neon_consts: 1093 .short 19595, 38470, 7471, 11059 1094 .short 21709, 32768, 27439, 5329 1095 .short 32767, 128, 32767, 128 1096 .short 32767, 128, 32767, 128 1097 1098asm_function jsimd_\colorid\()_ycc_convert_neon 1099 OUTPUT_WIDTH .req r0 1100 INPUT_BUF .req r1 1101 OUTPUT_BUF .req r2 1102 OUTPUT_ROW .req r3 1103 NUM_ROWS .req r4 1104 1105 OUTPUT_BUF0 .req r5 1106 OUTPUT_BUF1 .req r6 1107 OUTPUT_BUF2 .req OUTPUT_BUF 1108 1109 RGB .req r7 1110 Y .req r8 1111 U .req r9 1112 V .req r10 1113 N .req ip 1114 1115 /* Load constants to d0, d1, d2, d3 */ 1116 adr ip, jsimd_\colorid\()_ycc_neon_consts 1117 vld1.16 {d0, d1, d2, d3}, [ip, :128] 1118 1119 /* Save ARM registers and handle input arguments */ 1120 push {r4, r5, r6, r7, r8, r9, r10, lr} 1121 ldr NUM_ROWS, [sp, #(4 * 8)] 1122 ldr OUTPUT_BUF0, [OUTPUT_BUF] 1123 ldr OUTPUT_BUF1, [OUTPUT_BUF, #4] 1124 ldr OUTPUT_BUF2, [OUTPUT_BUF, #8] 1125 .unreq OUTPUT_BUF 1126 1127 /* Save NEON registers */ 1128 vpush {d8-d15} 1129 1130 /* Outer loop over scanlines */ 1131 cmp NUM_ROWS, #1 1132 blt 9f 11330: 1134 ldr Y, [OUTPUT_BUF0, OUTPUT_ROW, lsl #2] 1135 ldr U, [OUTPUT_BUF1, OUTPUT_ROW, lsl #2] 1136 mov N, OUTPUT_WIDTH 1137 ldr V, [OUTPUT_BUF2, OUTPUT_ROW, lsl #2] 1138 add OUTPUT_ROW, OUTPUT_ROW, #1 1139 ldr RGB, [INPUT_BUF], #4 1140 1141 /* Inner loop over pixels */ 1142 subs N, N, #8 1143 blt 3f 1144 do_load \bpp, 8 1145 do_rgb_to_yuv_stage1 1146 subs N, N, #8 1147 blt 2f 11481: 1149 do_rgb_to_yuv_stage2_store_load_stage1 1150 subs N, N, #8 1151 bge 1b 11522: 1153 do_rgb_to_yuv_stage2 1154 do_store 8 1155 tst N, #7 1156 beq 8f 11573: 1158 tst N, #4 1159 beq 3f 1160 do_load \bpp, 4 11613: 1162 tst N, #2 1163 beq 4f 1164 do_load \bpp, 2 11654: 1166 tst N, #1 1167 beq 5f 1168 do_load \bpp, 1 11695: 1170 do_rgb_to_yuv 1171 tst N, #4 1172 beq 6f 1173 do_store 4 11746: 1175 tst N, #2 1176 beq 7f 1177 do_store 2 11787: 1179 tst N, #1 1180 beq 8f 1181 do_store 1 11828: 1183 subs NUM_ROWS, NUM_ROWS, #1 1184 bgt 0b 11859: 1186 /* Restore all registers and return */ 1187 vpop {d8-d15} 1188 pop {r4, r5, r6, r7, r8, r9, r10, pc} 1189 1190 .unreq OUTPUT_WIDTH 1191 .unreq OUTPUT_ROW 1192 .unreq INPUT_BUF 1193 .unreq NUM_ROWS 1194 .unreq OUTPUT_BUF0 1195 .unreq OUTPUT_BUF1 1196 .unreq OUTPUT_BUF2 1197 .unreq RGB 1198 .unreq Y 1199 .unreq U 1200 .unreq V 1201 .unreq N 1202.endfunc 1203 1204.purgem do_rgb_to_yuv 1205.purgem do_rgb_to_yuv_stage1 1206.purgem do_rgb_to_yuv_stage2 1207.purgem do_rgb_to_yuv_stage2_store_load_stage1 1208 1209.endm 1210 1211/*--------------------------------- id ----- bpp R G B */ 1212generate_jsimd_rgb_ycc_convert_neon extrgb, 24, 0, 1, 2 1213generate_jsimd_rgb_ycc_convert_neon extbgr, 24, 2, 1, 0 1214generate_jsimd_rgb_ycc_convert_neon extrgbx, 32, 0, 1, 2 1215generate_jsimd_rgb_ycc_convert_neon extbgrx, 32, 2, 1, 0 1216generate_jsimd_rgb_ycc_convert_neon extxbgr, 32, 3, 2, 1 1217generate_jsimd_rgb_ycc_convert_neon extxrgb, 32, 1, 2, 3 1218 1219.purgem do_load 1220.purgem do_store 1221 1222/*****************************************************************************/ 1223 1224/* 1225 * Load data into workspace, applying unsigned->signed conversion 1226 * 1227 * TODO: can be combined with 'jsimd_fdct_ifast_neon' to get 1228 * rid of VST1.16 instructions 1229 */ 1230 1231asm_function jsimd_convsamp_neon 1232 SAMPLE_DATA .req r0 1233 START_COL .req r1 1234 WORKSPACE .req r2 1235 TMP1 .req r3 1236 TMP2 .req r4 1237 TMP3 .req r5 1238 TMP4 .req ip 1239 1240 push {r4, r5} 1241 vmov.u8 d0, #128 1242 1243 ldmia SAMPLE_DATA!, {TMP1, TMP2, TMP3, TMP4} 1244 add TMP1, TMP1, START_COL 1245 add TMP2, TMP2, START_COL 1246 add TMP3, TMP3, START_COL 1247 add TMP4, TMP4, START_COL 1248 vld1.8 {d16}, [TMP1] 1249 vsubl.u8 q8, d16, d0 1250 vld1.8 {d18}, [TMP2] 1251 vsubl.u8 q9, d18, d0 1252 vld1.8 {d20}, [TMP3] 1253 vsubl.u8 q10, d20, d0 1254 vld1.8 {d22}, [TMP4] 1255 ldmia SAMPLE_DATA!, {TMP1, TMP2, TMP3, TMP4} 1256 vsubl.u8 q11, d22, d0 1257 vst1.16 {d16, d17, d18, d19}, [WORKSPACE, :128]! 1258 add TMP1, TMP1, START_COL 1259 add TMP2, TMP2, START_COL 1260 vst1.16 {d20, d21, d22, d23}, [WORKSPACE, :128]! 1261 add TMP3, TMP3, START_COL 1262 add TMP4, TMP4, START_COL 1263 vld1.8 {d24}, [TMP1] 1264 vsubl.u8 q12, d24, d0 1265 vld1.8 {d26}, [TMP2] 1266 vsubl.u8 q13, d26, d0 1267 vld1.8 {d28}, [TMP3] 1268 vsubl.u8 q14, d28, d0 1269 vld1.8 {d30}, [TMP4] 1270 vsubl.u8 q15, d30, d0 1271 vst1.16 {d24, d25, d26, d27}, [WORKSPACE, :128]! 1272 vst1.16 {d28, d29, d30, d31}, [WORKSPACE, :128]! 1273 pop {r4, r5} 1274 bx lr 1275 1276 .unreq SAMPLE_DATA 1277 .unreq START_COL 1278 .unreq WORKSPACE 1279 .unreq TMP1 1280 .unreq TMP2 1281 .unreq TMP3 1282 .unreq TMP4 1283.endfunc 1284 1285/*****************************************************************************/ 1286 1287/* 1288 * jsimd_fdct_ifast_neon 1289 * 1290 * This function contains a fast, not so accurate integer implementation of 1291 * the forward DCT (Discrete Cosine Transform). It uses the same calculations 1292 * and produces exactly the same output as IJG's original 'jpeg_fdct_ifast' 1293 * function from jfdctfst.c 1294 * 1295 * TODO: can be combined with 'jsimd_convsamp_neon' to get 1296 * rid of a bunch of VLD1.16 instructions 1297 */ 1298 1299#define XFIX_0_382683433 d0[0] 1300#define XFIX_0_541196100 d0[1] 1301#define XFIX_0_707106781 d0[2] 1302#define XFIX_1_306562965 d0[3] 1303 1304.balign 16 1305jsimd_fdct_ifast_neon_consts: 1306 .short (98 * 128) /* XFIX_0_382683433 */ 1307 .short (139 * 128) /* XFIX_0_541196100 */ 1308 .short (181 * 128) /* XFIX_0_707106781 */ 1309 .short (334 * 128 - 256 * 128) /* XFIX_1_306562965 */ 1310 1311asm_function jsimd_fdct_ifast_neon 1312 1313 DATA .req r0 1314 TMP .req ip 1315 1316 vpush {d8-d15} 1317 1318 /* Load constants */ 1319 adr TMP, jsimd_fdct_ifast_neon_consts 1320 vld1.16 {d0}, [TMP, :64] 1321 1322 /* Load all DATA into NEON registers with the following allocation: 1323 * 0 1 2 3 | 4 5 6 7 1324 * ---------+-------- 1325 * 0 | d16 | d17 | q8 1326 * 1 | d18 | d19 | q9 1327 * 2 | d20 | d21 | q10 1328 * 3 | d22 | d23 | q11 1329 * 4 | d24 | d25 | q12 1330 * 5 | d26 | d27 | q13 1331 * 6 | d28 | d29 | q14 1332 * 7 | d30 | d31 | q15 1333 */ 1334 1335 vld1.16 {d16, d17, d18, d19}, [DATA, :128]! 1336 vld1.16 {d20, d21, d22, d23}, [DATA, :128]! 1337 vld1.16 {d24, d25, d26, d27}, [DATA, :128]! 1338 vld1.16 {d28, d29, d30, d31}, [DATA, :128] 1339 sub DATA, DATA, #(128 - 32) 1340 1341 mov TMP, #2 13421: 1343 /* Transpose */ 1344 vtrn.16 q12, q13 1345 vtrn.16 q10, q11 1346 vtrn.16 q8, q9 1347 vtrn.16 q14, q15 1348 vtrn.32 q9, q11 1349 vtrn.32 q13, q15 1350 vtrn.32 q8, q10 1351 vtrn.32 q12, q14 1352 vswp d30, d23 1353 vswp d24, d17 1354 vswp d26, d19 1355 /* 1-D FDCT */ 1356 vadd.s16 q2, q11, q12 1357 vswp d28, d21 1358 vsub.s16 q12, q11, q12 1359 vsub.s16 q6, q10, q13 1360 vadd.s16 q10, q10, q13 1361 vsub.s16 q7, q9, q14 1362 vadd.s16 q9, q9, q14 1363 vsub.s16 q1, q8, q15 1364 vadd.s16 q8, q8, q15 1365 vsub.s16 q4, q9, q10 1366 vsub.s16 q5, q8, q2 1367 vadd.s16 q3, q9, q10 1368 vadd.s16 q4, q4, q5 1369 vadd.s16 q2, q8, q2 1370 vqdmulh.s16 q4, q4, XFIX_0_707106781 1371 vadd.s16 q11, q12, q6 1372 vadd.s16 q8, q2, q3 1373 vsub.s16 q12, q2, q3 1374 vadd.s16 q3, q6, q7 1375 vadd.s16 q7, q7, q1 1376 vqdmulh.s16 q3, q3, XFIX_0_707106781 1377 vsub.s16 q6, q11, q7 1378 vadd.s16 q10, q5, q4 1379 vqdmulh.s16 q6, q6, XFIX_0_382683433 1380 vsub.s16 q14, q5, q4 1381 vqdmulh.s16 q11, q11, XFIX_0_541196100 1382 vqdmulh.s16 q5, q7, XFIX_1_306562965 1383 vadd.s16 q4, q1, q3 1384 vsub.s16 q3, q1, q3 1385 vadd.s16 q7, q7, q6 1386 vadd.s16 q11, q11, q6 1387 vadd.s16 q7, q7, q5 1388 vadd.s16 q13, q3, q11 1389 vsub.s16 q11, q3, q11 1390 vadd.s16 q9, q4, q7 1391 vsub.s16 q15, q4, q7 1392 subs TMP, TMP, #1 1393 bne 1b 1394 1395 /* store results */ 1396 vst1.16 {d16, d17, d18, d19}, [DATA, :128]! 1397 vst1.16 {d20, d21, d22, d23}, [DATA, :128]! 1398 vst1.16 {d24, d25, d26, d27}, [DATA, :128]! 1399 vst1.16 {d28, d29, d30, d31}, [DATA, :128] 1400 1401 vpop {d8-d15} 1402 bx lr 1403 1404 .unreq DATA 1405 .unreq TMP 1406.endfunc 1407 1408/*****************************************************************************/ 1409 1410/* 1411 * GLOBAL(void) 1412 * jsimd_quantize_neon (JCOEFPTR coef_block, DCTELEM * divisors, 1413 * DCTELEM * workspace); 1414 * 1415 * Note: the code uses 2 stage pipelining in order to improve instructions 1416 * scheduling and eliminate stalls (this provides ~15% better 1417 * performance for this function on both ARM Cortex-A8 and 1418 * ARM Cortex-A9 when compared to the non-pipelined variant). 1419 * The instructions which belong to the second stage use different 1420 * indentation for better readiability. 1421 */ 1422asm_function jsimd_quantize_neon 1423 1424 COEF_BLOCK .req r0 1425 DIVISORS .req r1 1426 WORKSPACE .req r2 1427 1428 RECIPROCAL .req DIVISORS 1429 CORRECTION .req r3 1430 SHIFT .req ip 1431 LOOP_COUNT .req r4 1432 1433 vld1.16 {d0, d1, d2, d3}, [WORKSPACE, :128]! 1434 vabs.s16 q12, q0 1435 add CORRECTION, DIVISORS, #(64 * 2) 1436 add SHIFT, DIVISORS, #(64 * 6) 1437 vld1.16 {d20, d21, d22, d23}, [CORRECTION, :128]! 1438 vabs.s16 q13, q1 1439 vld1.16 {d16, d17, d18, d19}, [RECIPROCAL, :128]! 1440 vadd.u16 q12, q12, q10 /* add correction */ 1441 vadd.u16 q13, q13, q11 1442 vmull.u16 q10, d24, d16 /* multiply by reciprocal */ 1443 vmull.u16 q11, d25, d17 1444 vmull.u16 q8, d26, d18 1445 vmull.u16 q9, d27, d19 1446 vld1.16 {d24, d25, d26, d27}, [SHIFT, :128]! 1447 vshrn.u32 d20, q10, #16 1448 vshrn.u32 d21, q11, #16 1449 vshrn.u32 d22, q8, #16 1450 vshrn.u32 d23, q9, #16 1451 vneg.s16 q12, q12 1452 vneg.s16 q13, q13 1453 vshr.s16 q2, q0, #15 /* extract sign */ 1454 vshr.s16 q3, q1, #15 1455 vshl.u16 q14, q10, q12 /* shift */ 1456 vshl.u16 q15, q11, q13 1457 1458 push {r4, r5} 1459 mov LOOP_COUNT, #3 14601: 1461 vld1.16 {d0, d1, d2, d3}, [WORKSPACE, :128]! 1462 veor.u16 q14, q14, q2 /* restore sign */ 1463 vabs.s16 q12, q0 1464 vld1.16 {d20, d21, d22, d23}, [CORRECTION, :128]! 1465 vabs.s16 q13, q1 1466 veor.u16 q15, q15, q3 1467 vld1.16 {d16, d17, d18, d19}, [RECIPROCAL, :128]! 1468 vadd.u16 q12, q12, q10 /* add correction */ 1469 vadd.u16 q13, q13, q11 1470 vmull.u16 q10, d24, d16 /* multiply by reciprocal */ 1471 vmull.u16 q11, d25, d17 1472 vmull.u16 q8, d26, d18 1473 vmull.u16 q9, d27, d19 1474 vsub.u16 q14, q14, q2 1475 vld1.16 {d24, d25, d26, d27}, [SHIFT, :128]! 1476 vsub.u16 q15, q15, q3 1477 vshrn.u32 d20, q10, #16 1478 vshrn.u32 d21, q11, #16 1479 vst1.16 {d28, d29, d30, d31}, [COEF_BLOCK, :128]! 1480 vshrn.u32 d22, q8, #16 1481 vshrn.u32 d23, q9, #16 1482 vneg.s16 q12, q12 1483 vneg.s16 q13, q13 1484 vshr.s16 q2, q0, #15 /* extract sign */ 1485 vshr.s16 q3, q1, #15 1486 vshl.u16 q14, q10, q12 /* shift */ 1487 vshl.u16 q15, q11, q13 1488 subs LOOP_COUNT, LOOP_COUNT, #1 1489 bne 1b 1490 pop {r4, r5} 1491 1492 veor.u16 q14, q14, q2 /* restore sign */ 1493 veor.u16 q15, q15, q3 1494 vsub.u16 q14, q14, q2 1495 vsub.u16 q15, q15, q3 1496 vst1.16 {d28, d29, d30, d31}, [COEF_BLOCK, :128]! 1497 1498 bx lr /* return */ 1499 1500 .unreq COEF_BLOCK 1501 .unreq DIVISORS 1502 .unreq WORKSPACE 1503 .unreq RECIPROCAL 1504 .unreq CORRECTION 1505 .unreq SHIFT 1506 .unreq LOOP_COUNT 1507.endfunc 1508