1 /* 2 * Copyright 2011 The LibYuv Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "libyuv/row.h" 12 13 #ifdef __cplusplus 14 namespace libyuv { 15 extern "C" { 16 #endif 17 18 // This module is for GCC Neon 19 #if !defined(YUV_DISABLE_ASM) && defined(__ARM_NEON__) 20 21 // Read 8 Y, 4 U and 4 V from 422 22 #define READYUV422 \ 23 "vld1.u8 {d0}, [%0]! \n" \ 24 "vld1.u32 {d2[0]}, [%1]! \n" \ 25 "vld1.u32 {d2[1]}, [%2]! \n" 26 27 // Read 8 Y and 4 UV from NV12 28 #define READNV12 \ 29 "vld1.u8 {d0}, [%0]! \n" \ 30 "vld1.u8 {d2}, [%1]! \n" \ 31 "vmov.u8 d3, d2 \n"/* split odd/even uv apart */\ 32 "vuzp.u8 d2, d3 \n" \ 33 "vtrn.u32 d2, d3 \n" \ 34 35 // Read 8 Y and 4 VU from NV21 36 #define READNV21 \ 37 "vld1.u8 {d0}, [%0]! \n" \ 38 "vld1.u8 {d2}, [%1]! \n" \ 39 "vmov.u8 d3, d2 \n"/* split odd/even uv apart */\ 40 "vuzp.u8 d3, d2 \n" \ 41 "vtrn.u32 d2, d3 \n" \ 42 43 #define YUV422TORGB \ 44 "veor.u8 d2, d26 \n"/*subtract 128 from u and v*/\ 45 "vmull.s8 q8, d2, d24 \n"/* u/v B/R component */\ 46 "vmull.s8 q9, d2, d25 \n"/* u/v G component */\ 47 "vmov.u8 d1, #0 \n"/* split odd/even y apart */\ 48 "vtrn.u8 d0, d1 \n" \ 49 "vsub.s16 q0, q0, q15 \n"/* offset y */\ 50 "vmul.s16 q0, q0, q14 \n" \ 51 "vadd.s16 d18, d19 \n" \ 52 "vqadd.s16 d20, d0, d16 \n" \ 53 "vqadd.s16 d21, d1, d16 \n" \ 54 "vqadd.s16 d22, d0, d17 \n" \ 55 "vqadd.s16 d23, d1, d17 \n" \ 56 "vqadd.s16 d16, d0, d18 \n" \ 57 "vqadd.s16 d17, d1, d18 \n" \ 58 "vqrshrun.s16 d0, q10, #6 \n" \ 59 "vqrshrun.s16 d1, q11, #6 \n" \ 60 "vqrshrun.s16 d2, q8, #6 \n" \ 61 "vmovl.u8 q10, d0 \n"/* set up for reinterleave*/\ 62 "vmovl.u8 q11, d1 \n" \ 63 "vmovl.u8 q8, d2 \n" \ 64 "vtrn.u8 d20, d21 \n" \ 65 "vtrn.u8 d22, d23 \n" \ 66 "vtrn.u8 d16, d17 \n" \ 67 "vmov.u8 d21, d16 \n" 68 69 #if defined(HAS_I422TOARGBROW_NEON) || defined(HAS_I422TOBGRAROW_NEON) || \ 70 defined(HAS_I422TOABGRROW_NEON) || defined(HAS_I422TORGBAROW_NEON) 71 static const vec8 kUVToRB = { 127, 127, 127, 127, 102, 102, 102, 102, 72 0, 0, 0, 0, 0, 0, 0, 0 }; 73 static const vec8 kUVToG = { -25, -25, -25, -25, -52, -52, -52, -52, 74 0, 0, 0, 0, 0, 0, 0, 0 }; 75 #endif 76 77 #ifdef HAS_I422TOARGBROW_NEON 78 void I422ToARGBRow_NEON(const uint8* y_buf, 79 const uint8* u_buf, 80 const uint8* v_buf, 81 uint8* rgb_buf, 82 int width) { 83 asm volatile ( 84 "vld1.u8 {d24}, [%5] \n" 85 "vld1.u8 {d25}, [%6] \n" 86 "vmov.u8 d26, #128 \n" 87 "vmov.u16 q14, #74 \n" 88 "vmov.u16 q15, #16 \n" 89 ".p2align 2 \n" 90 "1: \n" 91 READYUV422 92 YUV422TORGB 93 "subs %4, %4, #8 \n" 94 "vmov.u8 d23, #255 \n" 95 "vst4.8 {d20, d21, d22, d23}, [%3]! \n" 96 "bgt 1b \n" 97 : "+r"(y_buf), // %0 98 "+r"(u_buf), // %1 99 "+r"(v_buf), // %2 100 "+r"(rgb_buf), // %3 101 "+r"(width) // %4 102 : "r"(&kUVToRB), // %5 103 "r"(&kUVToG) // %6 104 : "cc", "memory", "q0", "q1", "q2", "q3", 105 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 106 ); 107 } 108 #endif // HAS_I422TOARGBROW_NEON 109 110 #ifdef HAS_I422TOBGRAROW_NEON 111 void I422ToBGRARow_NEON(const uint8* y_buf, 112 const uint8* u_buf, 113 const uint8* v_buf, 114 uint8* rgb_buf, 115 int width) { 116 asm volatile ( 117 "vld1.u8 {d24}, [%5] \n" 118 "vld1.u8 {d25}, [%6] \n" 119 "vmov.u8 d26, #128 \n" 120 "vmov.u16 q14, #74 \n" 121 "vmov.u16 q15, #16 \n" 122 ".p2align 2 \n" 123 "1: \n" 124 READYUV422 125 YUV422TORGB 126 "subs %4, %4, #8 \n" 127 "vswp.u8 d20, d22 \n" 128 "vmov.u8 d19, #255 \n" 129 "vst4.8 {d19, d20, d21, d22}, [%3]! \n" 130 "bgt 1b \n" 131 : "+r"(y_buf), // %0 132 "+r"(u_buf), // %1 133 "+r"(v_buf), // %2 134 "+r"(rgb_buf), // %3 135 "+r"(width) // %4 136 : "r"(&kUVToRB), // %5 137 "r"(&kUVToG) // %6 138 : "cc", "memory", "q0", "q1", "q2", "q3", 139 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 140 ); 141 } 142 #endif // HAS_I422TOBGRAROW_NEON 143 144 #ifdef HAS_I422TOABGRROW_NEON 145 void I422ToABGRRow_NEON(const uint8* y_buf, 146 const uint8* u_buf, 147 const uint8* v_buf, 148 uint8* rgb_buf, 149 int width) { 150 asm volatile ( 151 "vld1.u8 {d24}, [%5] \n" 152 "vld1.u8 {d25}, [%6] \n" 153 "vmov.u8 d26, #128 \n" 154 "vmov.u16 q14, #74 \n" 155 "vmov.u16 q15, #16 \n" 156 ".p2align 2 \n" 157 "1: \n" 158 READYUV422 159 YUV422TORGB 160 "subs %4, %4, #8 \n" 161 "vswp.u8 d20, d22 \n" 162 "vmov.u8 d23, #255 \n" 163 "vst4.8 {d20, d21, d22, d23}, [%3]! \n" 164 "bgt 1b \n" 165 : "+r"(y_buf), // %0 166 "+r"(u_buf), // %1 167 "+r"(v_buf), // %2 168 "+r"(rgb_buf), // %3 169 "+r"(width) // %4 170 : "r"(&kUVToRB), // %5 171 "r"(&kUVToG) // %6 172 : "cc", "memory", "q0", "q1", "q2", "q3", 173 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 174 ); 175 } 176 #endif // HAS_I422TOABGRROW_NEON 177 178 #ifdef HAS_I422TORGBAROW_NEON 179 void I422ToRGBARow_NEON(const uint8* y_buf, 180 const uint8* u_buf, 181 const uint8* v_buf, 182 uint8* rgb_buf, 183 int width) { 184 asm volatile ( 185 "vld1.u8 {d24}, [%5] \n" 186 "vld1.u8 {d25}, [%6] \n" 187 "vmov.u8 d26, #128 \n" 188 "vmov.u16 q14, #74 \n" 189 "vmov.u16 q15, #16 \n" 190 ".p2align 2 \n" 191 "1: \n" 192 READYUV422 193 YUV422TORGB 194 "subs %4, %4, #8 \n" 195 "vmov.u8 d19, #255 \n" 196 "vst4.8 {d19, d20, d21, d22}, [%3]! \n" 197 "bgt 1b \n" 198 : "+r"(y_buf), // %0 199 "+r"(u_buf), // %1 200 "+r"(v_buf), // %2 201 "+r"(rgb_buf), // %3 202 "+r"(width) // %4 203 : "r"(&kUVToRB), // %5 204 "r"(&kUVToG) // %6 205 : "cc", "memory", "q0", "q1", "q2", "q3", 206 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 207 ); 208 } 209 #endif // HAS_I422TORGBAROW_NEON 210 211 #ifdef HAS_I422TORGB24ROW_NEON 212 void I422ToRGB24Row_NEON(const uint8* y_buf, 213 const uint8* u_buf, 214 const uint8* v_buf, 215 uint8* rgb_buf, 216 int width) { 217 asm volatile ( 218 "vld1.u8 {d24}, [%5] \n" 219 "vld1.u8 {d25}, [%6] \n" 220 "vmov.u8 d26, #128 \n" 221 "vmov.u16 q14, #74 \n" 222 "vmov.u16 q15, #16 \n" 223 ".p2align 2 \n" 224 "1: \n" 225 READYUV422 226 YUV422TORGB 227 "subs %4, %4, #8 \n" 228 "vst3.8 {d20, d21, d22}, [%3]! \n" 229 "bgt 1b \n" 230 : "+r"(y_buf), // %0 231 "+r"(u_buf), // %1 232 "+r"(v_buf), // %2 233 "+r"(rgb_buf), // %3 234 "+r"(width) // %4 235 : "r"(&kUVToRB), // %5 236 "r"(&kUVToG) // %6 237 : "cc", "memory", "q0", "q1", "q2", "q3", 238 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 239 ); 240 } 241 #endif // HAS_I422TORGB24ROW_NEON 242 243 #ifdef HAS_I422TORAWROW_NEON 244 void I422ToRAWRow_NEON(const uint8* y_buf, 245 const uint8* u_buf, 246 const uint8* v_buf, 247 uint8* rgb_buf, 248 int width) { 249 asm volatile ( 250 "vld1.u8 {d24}, [%5] \n" 251 "vld1.u8 {d25}, [%6] \n" 252 "vmov.u8 d26, #128 \n" 253 "vmov.u16 q14, #74 \n" 254 "vmov.u16 q15, #16 \n" 255 ".p2align 2 \n" 256 "1: \n" 257 READYUV422 258 YUV422TORGB 259 "subs %4, %4, #8 \n" 260 "vswp.u8 d20, d22 \n" 261 "vst3.8 {d20, d21, d22}, [%3]! \n" 262 "bgt 1b \n" 263 : "+r"(y_buf), // %0 264 "+r"(u_buf), // %1 265 "+r"(v_buf), // %2 266 "+r"(rgb_buf), // %3 267 "+r"(width) // %4 268 : "r"(&kUVToRB), // %5 269 "r"(&kUVToG) // %6 270 : "cc", "memory", "q0", "q1", "q2", "q3", 271 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 272 ); 273 } 274 #endif // HAS_I422TORAWROW_NEON 275 276 #ifdef HAS_NV12TOARGBROW_NEON 277 void NV12ToARGBRow_NEON(const uint8* y_buf, 278 const uint8* uv_buf, 279 uint8* rgb_buf, 280 int width) { 281 asm volatile ( 282 "vld1.u8 {d24}, [%4] \n" 283 "vld1.u8 {d25}, [%5] \n" 284 "vmov.u8 d26, #128 \n" 285 "vmov.u16 q14, #74 \n" 286 "vmov.u16 q15, #16 \n" 287 ".p2align 2 \n" 288 "1: \n" 289 READNV12 290 YUV422TORGB 291 "subs %3, %3, #8 \n" 292 "vmov.u8 d23, #255 \n" 293 "vst4.8 {d20, d21, d22, d23}, [%2]! \n" 294 "bgt 1b \n" 295 : "+r"(y_buf), // %0 296 "+r"(uv_buf), // %1 297 "+r"(rgb_buf), // %2 298 "+r"(width) // %3 299 : "r"(&kUVToRB), // %4 300 "r"(&kUVToG) // %5 301 : "cc", "memory", "q0", "q1", "q2", "q3", 302 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 303 ); 304 } 305 #endif // HAS_NV12TOARGBROW_NEON 306 307 #ifdef HAS_NV21TOARGBROW_NEON 308 void NV21ToARGBRow_NEON(const uint8* y_buf, 309 const uint8* uv_buf, 310 uint8* rgb_buf, 311 int width) { 312 asm volatile ( 313 "vld1.u8 {d24}, [%4] \n" 314 "vld1.u8 {d25}, [%5] \n" 315 "vmov.u8 d26, #128 \n" 316 "vmov.u16 q14, #74 \n" 317 "vmov.u16 q15, #16 \n" 318 ".p2align 2 \n" 319 "1: \n" 320 READNV21 321 YUV422TORGB 322 "subs %3, %3, #8 \n" 323 "vmov.u8 d23, #255 \n" 324 "vst4.8 {d20, d21, d22, d23}, [%2]! \n" 325 "bgt 1b \n" 326 : "+r"(y_buf), // %0 327 "+r"(uv_buf), // %1 328 "+r"(rgb_buf), // %2 329 "+r"(width) // %3 330 : "r"(&kUVToRB), // %4 331 "r"(&kUVToG) // %5 332 : "cc", "memory", "q0", "q1", "q2", "q3", 333 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 334 ); 335 } 336 #endif // HAS_NV21TOARGBROW_NEON 337 338 #ifdef HAS_SPLITUV_NEON 339 // Reads 16 pairs of UV and write even values to dst_u and odd to dst_v 340 // Alignment requirement: 16 bytes for pointers, and multiple of 16 pixels. 341 void SplitUV_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width) { 342 asm volatile ( 343 ".p2align 2 \n" 344 "1: \n" 345 "vld2.u8 {q0, q1}, [%0]! \n" // load 16 pairs of UV 346 "subs %3, %3, #16 \n" // 16 processed per loop 347 "vst1.u8 {q0}, [%1]! \n" // store U 348 "vst1.u8 {q1}, [%2]! \n" // Store V 349 "bgt 1b \n" 350 : "+r"(src_uv), // %0 351 "+r"(dst_u), // %1 352 "+r"(dst_v), // %2 353 "+r"(width) // %3 // Output registers 354 : // Input registers 355 : "memory", "cc", "q0", "q1" // Clobber List 356 ); 357 } 358 #endif // HAS_SPLITUV_NEON 359 360 #ifdef HAS_COPYROW_NEON 361 // Copy multiple of 64 362 void CopyRow_NEON(const uint8* src, uint8* dst, int count) { 363 asm volatile ( 364 ".p2align 2 \n" 365 "1: \n" 366 "vldm %0!, {q0, q1, q2, q3} \n" // load 64 367 "subs %2, %2, #64 \n" // 64 processed per loop 368 "vstm %1!, {q0, q1, q2, q3} \n" // store 64 369 "bgt 1b \n" 370 : "+r"(src), // %0 371 "+r"(dst), // %1 372 "+r"(count) // %2 // Output registers 373 : // Input registers 374 : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List 375 ); 376 } 377 #endif // HAS_COPYROW_NEON 378 379 #ifdef HAS_SETROW_NEON 380 // SetRow8 writes 'count' bytes using a 32 bit value repeated. 381 void SetRow8_NEON(uint8* dst, uint32 v32, int count) { 382 asm volatile ( // NOLINT 383 "vdup.u32 q0, %2 \n" // duplicate 4 ints 384 "1: \n" 385 "subs %1, %1, #16 \n" // 16 bytes per loop 386 "vst1.u32 {q0}, [%0]! \n" // store 387 "bgt 1b \n" 388 : "+r"(dst), // %0 389 "+r"(count) // %1 390 : "r"(v32) // %2 391 : "q0", "memory", "cc"); 392 } 393 394 // TODO(fbarchard): Make fully assembler 395 // SetRow32 writes 'count' words using a 32 bit value repeated. 396 void SetRows32_NEON(uint8* dst, uint32 v32, int width, 397 int dst_stride, int height) { 398 for (int y = 0; y < height; ++y) { 399 SetRow8_NEON(dst, v32, width << 2); 400 dst += dst_stride; 401 } 402 } 403 #endif // HAS_SETROW_NEON 404 405 #ifdef HAS_MIRRORROW_NEON 406 void MirrorRow_NEON(const uint8* src, uint8* dst, int width) { 407 asm volatile ( 408 // compute where to start writing destination 409 "add %1, %2 \n" 410 // work on segments that are multiples of 16 411 "lsrs r3, %2, #4 \n" 412 // the output is written in two block. 8 bytes followed 413 // by another 8. reading is done sequentially, from left to 414 // right. writing is done from right to left in block sizes 415 // %1, the destination pointer is incremented after writing 416 // the first of the two blocks. need to subtract that 8 off 417 // along with 16 to get the next location. 418 "mov r3, #-24 \n" 419 "beq 2f \n" 420 421 // back of destination by the size of the register that is 422 // going to be mirrored 423 "sub %1, #16 \n" 424 // the loop needs to run on blocks of 16. what will be left 425 // over is either a negative number, the residuals that need 426 // to be done, or 0. If this isn't subtracted off here the 427 // loop will run one extra time. 428 "sub %2, #16 \n" 429 430 // mirror the bytes in the 64 bit segments. unable to mirror 431 // the bytes in the entire 128 bits in one go. 432 // because of the inability to mirror the entire 128 bits 433 // mirror the writing out of the two 64 bit segments. 434 ".p2align 2 \n" 435 "1: \n" 436 "vld1.8 {q0}, [%0]! \n" // src += 16 437 "subs %2, #16 \n" 438 "vrev64.8 q0, q0 \n" 439 "vst1.8 {d1}, [%1]! \n" 440 "vst1.8 {d0}, [%1], r3 \n" // dst -= 16 441 "bge 1b \n" 442 443 // add 16 back to the counter. if the result is 0 there is no 444 // residuals so jump past 445 "adds %2, #16 \n" 446 "beq 5f \n" 447 "add %1, #16 \n" 448 "2: \n" 449 "mov r3, #-3 \n" 450 "sub %1, #2 \n" 451 "subs %2, #2 \n" 452 // check for 16*n+1 scenarios where segments_of_2 should not 453 // be run, but there is something left over. 454 "blt 4f \n" 455 456 // do this in neon registers as per 457 // http://blogs.arm.com/software-enablement/196-coding-for-neon-part-2-dealing-with-leftovers/ 458 "3: \n" 459 "vld2.8 {d0[0], d1[0]}, [%0]! \n" // src += 2 460 "subs %2, #2 \n" 461 "vst1.8 {d1[0]}, [%1]! \n" 462 "vst1.8 {d0[0]}, [%1], r3 \n" // dst -= 2 463 "bge 3b \n" 464 465 "adds %2, #2 \n" 466 "beq 5f \n" 467 "4: \n" 468 "add %1, #1 \n" 469 "vld1.8 {d0[0]}, [%0] \n" 470 "vst1.8 {d0[0]}, [%1] \n" 471 "5: \n" 472 : "+r"(src), // %0 473 "+r"(dst), // %1 474 "+r"(width) // %2 475 : 476 : "memory", "cc", "r3", "q0" 477 ); 478 } 479 #endif // HAS_MIRRORROW_NEON 480 481 #ifdef HAS_MIRRORROWUV_NEON 482 void MirrorRowUV_NEON(const uint8* src, uint8* dst_a, uint8* dst_b, int width) { 483 asm volatile ( 484 // compute where to start writing destination 485 "add %1, %3 \n" // dst_a + width 486 "add %2, %3 \n" // dst_b + width 487 // work on input segments that are multiples of 16, but 488 // width that has been passed is output segments, half 489 // the size of input. 490 "lsrs r12, %3, #3 \n" 491 "beq 2f \n" 492 // the output is written in to two blocks. 493 "mov r12, #-8 \n" 494 // back of destination by the size of the register that is 495 // going to be mirrord 496 "sub %1, #8 \n" 497 "sub %2, #8 \n" 498 // the loop needs to run on blocks of 8. what will be left 499 // over is either a negative number, the residuals that need 500 // to be done, or 0. if this isn't subtracted off here the 501 // loop will run one extra time. 502 "sub %3, #8 \n" 503 504 // mirror the bytes in the 64 bit segments 505 ".p2align 2 \n" 506 "1: \n" 507 "vld2.8 {d0, d1}, [%0]! \n" // src += 16 508 "subs %3, #8 \n" 509 "vrev64.8 q0, q0 \n" 510 "vst1.8 {d0}, [%1], r12 \n" // dst_a -= 8 511 "vst1.8 {d1}, [%2], r12 \n" // dst_b -= 8 512 "bge 1b \n" 513 514 // add 8 back to the counter. if the result is 0 there is no 515 // residuals so return 516 "adds %3, #8 \n" 517 "beq 4f \n" 518 "add %1, #8 \n" 519 "add %2, #8 \n" 520 "2: \n" 521 "mov r12, #-1 \n" 522 "sub %1, #1 \n" 523 "sub %2, #1 \n" 524 "3: \n" 525 "vld2.8 {d0[0], d1[0]}, [%0]! \n" // src += 2 526 "subs %3, %3, #1 \n" 527 "vst1.8 {d0[0]}, [%1], r12 \n" // dst_a -= 1 528 "vst1.8 {d1[0]}, [%2], r12 \n" // dst_b -= 1 529 "bgt 3b \n" 530 "4: \n" 531 : "+r"(src), // %0 532 "+r"(dst_a), // %1 533 "+r"(dst_b), // %2 534 "+r"(width) // %3 535 : 536 : "memory", "cc", "r12", "q0" 537 ); 538 } 539 #endif // HAS_MIRRORROWUV_NEON 540 541 #ifdef HAS_BGRATOARGBROW_NEON 542 void BGRAToARGBRow_NEON(const uint8* src_bgra, uint8* dst_argb, int pix) { 543 asm volatile ( 544 ".p2align 2 \n" 545 "1: \n" 546 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of BGRA. 547 "subs %2, %2, #8 \n" // 8 processed per loop. 548 "vswp.u8 d1, d2 \n" // swap G, R 549 "vswp.u8 d0, d3 \n" // swap B, A 550 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB. 551 "bgt 1b \n" 552 : "+r"(src_bgra), // %0 553 "+r"(dst_argb), // %1 554 "+r"(pix) // %2 555 : 556 : "memory", "cc", "d0", "d1", "d2", "d3" // Clobber List 557 ); 558 } 559 #endif // HAS_BGRATOARGBROW_NEON 560 561 #ifdef HAS_ABGRTOARGBROW_NEON 562 void ABGRToARGBRow_NEON(const uint8* src_abgr, uint8* dst_argb, int pix) { 563 asm volatile ( 564 ".p2align 2 \n" 565 "1: \n" 566 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ABGR. 567 "subs %2, %2, #8 \n" // 8 processed per loop. 568 "vswp.u8 d0, d2 \n" // swap R, B 569 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB. 570 "bgt 1b \n" 571 : "+r"(src_abgr), // %0 572 "+r"(dst_argb), // %1 573 "+r"(pix) // %2 574 : 575 : "memory", "cc", "d0", "d1", "d2", "d3" // Clobber List 576 ); 577 } 578 #endif // HAS_ABGRTOARGBROW_NEON 579 580 #ifdef HAS_RGBATOARGBROW_NEON 581 void RGBAToARGBRow_NEON(const uint8* src_rgba, uint8* dst_argb, int pix) { 582 asm volatile ( 583 ".p2align 2 \n" 584 "1: \n" 585 "vld1.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of RGBA. 586 "subs %2, %2, #8 \n" // 8 processed per loop. 587 "vmov.u8 d4, d0 \n" // move A after RGB 588 "vst4.8 {d1, d2, d3, d4}, [%1]! \n" // store 8 pixels of ARGB. 589 "bgt 1b \n" 590 : "+r"(src_rgba), // %0 591 "+r"(dst_argb), // %1 592 "+r"(pix) // %2 593 : 594 : "memory", "cc", "d0", "d1", "d2", "d3", "d4" // Clobber List 595 ); 596 } 597 #endif // HAS_RGBATOARGBROW_NEON 598 599 #ifdef HAS_RGB24TOARGBROW_NEON 600 void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix) { 601 asm volatile ( 602 "vmov.u8 d4, #255 \n" // Alpha 603 ".p2align 2 \n" 604 "1: \n" 605 "vld3.8 {d1, d2, d3}, [%0]! \n" // load 8 pixels of RGB24. 606 "subs %2, %2, #8 \n" // 8 processed per loop. 607 "vst4.8 {d1, d2, d3, d4}, [%1]! \n" // store 8 pixels of ARGB. 608 "bgt 1b \n" 609 : "+r"(src_rgb24), // %0 610 "+r"(dst_argb), // %1 611 "+r"(pix) // %2 612 : 613 : "memory", "cc", "d1", "d2", "d3", "d4" // Clobber List 614 ); 615 } 616 #endif // HAS_RGB24TOARGBROW_NEON 617 618 #ifdef HAS_RAWTOARGBROW_NEON 619 void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int pix) { 620 asm volatile ( 621 "vmov.u8 d4, #255 \n" // Alpha 622 ".p2align 2 \n" 623 "1: \n" 624 "vld3.8 {d1, d2, d3}, [%0]! \n" // load 8 pixels of RAW. 625 "subs %2, %2, #8 \n" // 8 processed per loop. 626 "vswp.u8 d1, d3 \n" // swap R, B 627 "vst4.8 {d1, d2, d3, d4}, [%1]! \n" // store 8 pixels of ARGB. 628 "bgt 1b \n" 629 : "+r"(src_raw), // %0 630 "+r"(dst_argb), // %1 631 "+r"(pix) // %2 632 : 633 : "memory", "cc", "d1", "d2", "d3", "d4" // Clobber List 634 ); 635 } 636 #endif // HAS_RAWTOARGBROW_NEON 637 638 #ifdef HAS_ARGBTORGBAROW_NEON 639 void ARGBToRGBARow_NEON(const uint8* src_argb, uint8* dst_rgba, int pix) { 640 asm volatile ( 641 ".p2align 2 \n" 642 "1: \n" 643 "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB. 644 "subs %2, %2, #8 \n" // 8 processed per loop. 645 "vmov.u8 d0, d4 \n" // move A before RGB. 646 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of RGBA. 647 "bgt 1b \n" 648 : "+r"(src_argb), // %0 649 "+r"(dst_rgba), // %1 650 "+r"(pix) // %2 651 : 652 : "memory", "cc", "d0", "d1", "d2", "d3", "d4" // Clobber List 653 ); 654 } 655 #endif // HAS_ARGBTORGBAROW_NEON 656 657 #ifdef HAS_ARGBTORGB24ROW_NEON 658 void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int pix) { 659 asm volatile ( 660 ".p2align 2 \n" 661 "1: \n" 662 "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB. 663 "subs %2, %2, #8 \n" // 8 processed per loop. 664 "vst3.8 {d1, d2, d3}, [%1]! \n" // store 8 pixels of RGB24. 665 "bgt 1b \n" 666 : "+r"(src_argb), // %0 667 "+r"(dst_rgb24), // %1 668 "+r"(pix) // %2 669 : 670 : "memory", "cc", "d1", "d2", "d3", "d4" // Clobber List 671 ); 672 } 673 #endif // HAS_ARGBTORGB24ROW_NEON 674 675 #ifdef HAS_ARGBTORAWROW_NEON 676 void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int pix) { 677 asm volatile ( 678 ".p2align 2 \n" 679 "1: \n" 680 "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB. 681 "subs %2, %2, #8 \n" // 8 processed per loop. 682 "vswp.u8 d1, d3 \n" // swap R, B 683 "vst3.8 {d1, d2, d3}, [%1]! \n" // store 8 pixels of RAW. 684 "bgt 1b \n" 685 : "+r"(src_argb), // %0 686 "+r"(dst_raw), // %1 687 "+r"(pix) // %2 688 : 689 : "memory", "cc", "d1", "d2", "d3", "d4" // Clobber List 690 ); 691 } 692 #endif // HAS_ARGBTORAWROW_NEON 693 694 #ifdef HAS_YUY2TOYROW_NEON 695 void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int pix) { 696 asm volatile ( 697 ".p2align 2 \n" 698 "1: \n" 699 "vld2.u8 {q0, q1}, [%0]! \n" // load 16 pixels of YUY2. 700 "subs %2, %2, #16 \n" // 16 processed per loop. 701 "vst1.u8 {q0}, [%1]! \n" // store 16 pixels of Y. 702 "bgt 1b \n" 703 : "+r"(src_yuy2), // %0 704 "+r"(dst_y), // %1 705 "+r"(pix) // %2 706 : 707 : "memory", "cc", "q0", "q1" // Clobber List 708 ); 709 } 710 #endif // HAS_YUY2TOYROW_NEON 711 712 #ifdef HAS_UYVYTOYROW_NEON 713 void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int pix) { 714 asm volatile ( 715 ".p2align 2 \n" 716 "1: \n" 717 "vld2.u8 {q0, q1}, [%0]! \n" // load 16 pixels of UYVY. 718 "subs %2, %2, #16 \n" // 16 processed per loop. 719 "vst1.u8 {q1}, [%1]! \n" // store 16 pixels of Y. 720 "bgt 1b \n" 721 : "+r"(src_uyvy), // %0 722 "+r"(dst_y), // %1 723 "+r"(pix) // %2 724 : 725 : "memory", "cc", "q0", "q1" // Clobber List 726 ); 727 } 728 #endif // HAS_UYVYTOYROW_NEON 729 730 #ifdef HAS_YUY2TOYROW_NEON 731 void YUY2ToUV422Row_NEON(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v, 732 int pix) { 733 asm volatile ( 734 ".p2align 2 \n" 735 "1: \n" 736 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of YUY2. 737 "subs %3, %3, #16 \n" // 16 pixels = 8 UVs. 738 "vst1.u8 {d1}, [%1]! \n" // store 8 U. 739 "vst1.u8 {d3}, [%2]! \n" // store 8 V. 740 "bgt 1b \n" 741 : "+r"(src_yuy2), // %0 742 "+r"(dst_u), // %1 743 "+r"(dst_v), // %2 744 "+r"(pix) // %3 745 : 746 : "memory", "cc", "d0", "d1", "d2", "d3" // Clobber List 747 ); 748 } 749 #endif // HAS_YUY2TOYROW_NEON 750 751 #ifdef HAS_UYVYTOYROW_NEON 752 void UYVYToUV422Row_NEON(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v, 753 int pix) { 754 asm volatile ( 755 ".p2align 2 \n" 756 "1: \n" 757 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of UYVY. 758 "subs %3, %3, #16 \n" // 16 pixels = 8 UVs. 759 "vst1.u8 {d0}, [%1]! \n" // store 8 U. 760 "vst1.u8 {d2}, [%2]! \n" // store 8 V. 761 "bgt 1b \n" 762 : "+r"(src_uyvy), // %0 763 "+r"(dst_u), // %1 764 "+r"(dst_v), // %2 765 "+r"(pix) // %3 766 : 767 : "memory", "cc", "d0", "d1", "d2", "d3" // Clobber List 768 ); 769 } 770 #endif // HAS_UYVYTOYROW_NEON 771 772 #ifdef HAS_YUY2TOYROW_NEON 773 void YUY2ToUVRow_NEON(const uint8* src_yuy2, int stride_yuy2, 774 uint8* dst_u, uint8* dst_v, int pix) { 775 asm volatile ( 776 "adds %1, %0, %1 \n" // stride + src_yuy2 777 ".p2align 2 \n" 778 "1: \n" 779 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of YUY2. 780 "subs %4, %4, #16 \n" // 16 pixels = 8 UVs. 781 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load next row YUY2. 782 "vrhadd.u8 d1, d1, d5 \n" // average rows of U 783 "vrhadd.u8 d3, d3, d7 \n" // average rows of V 784 "vst1.u8 {d1}, [%2]! \n" // store 8 U. 785 "vst1.u8 {d3}, [%3]! \n" // store 8 V. 786 "bgt 1b \n" 787 : "+r"(src_yuy2), // %0 788 "+r"(stride_yuy2), // %1 789 "+r"(dst_u), // %2 790 "+r"(dst_v), // %3 791 "+r"(pix) // %4 792 : 793 : "memory", "cc", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7" // Clobber List 794 ); 795 } 796 #endif // HAS_YUY2TOYROW_NEON 797 798 #ifdef HAS_UYVYTOYROW_NEON 799 void UYVYToUVRow_NEON(const uint8* src_uyvy, int stride_uyvy, 800 uint8* dst_u, uint8* dst_v, int pix) { 801 asm volatile ( 802 "adds %1, %0, %1 \n" // stride + src_uyvy 803 ".p2align 2 \n" 804 "1: \n" 805 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of UYVY. 806 "subs %4, %4, #16 \n" // 16 pixels = 8 UVs. 807 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load next row UYVY. 808 "vrhadd.u8 d0, d0, d4 \n" // average rows of U 809 "vrhadd.u8 d2, d2, d6 \n" // average rows of V 810 "vst1.u8 {d0}, [%2]! \n" // store 8 U. 811 "vst1.u8 {d2}, [%3]! \n" // store 8 V. 812 "bgt 1b \n" 813 : "+r"(src_uyvy), // %0 814 "+r"(stride_uyvy), // %1 815 "+r"(dst_u), // %2 816 "+r"(dst_v), // %3 817 "+r"(pix) // %4 818 : 819 : "memory", "cc", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7" // Clobber List 820 ); 821 } 822 #endif // HAS_UYVYTOYROW_NEON 823 824 #endif // __ARM_NEON__ 825 826 #ifdef __cplusplus 827 } // extern "C" 828 } // namespace libyuv 829 #endif 830