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(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__) 20 21 // Read 8 Y, 4 U and 4 V from 422 22 #define READYUV422 \ 23 MEMACCESS(0) \ 24 "vld1.8 {d0}, [%0]! \n" \ 25 MEMACCESS(1) \ 26 "vld1.32 {d2[0]}, [%1]! \n" \ 27 MEMACCESS(2) \ 28 "vld1.32 {d2[1]}, [%2]! \n" 29 30 // Read 8 Y, 2 U and 2 V from 422 31 #define READYUV411 \ 32 MEMACCESS(0) \ 33 "vld1.8 {d0}, [%0]! \n" \ 34 MEMACCESS(1) \ 35 "vld1.16 {d2[0]}, [%1]! \n" \ 36 MEMACCESS(2) \ 37 "vld1.16 {d2[1]}, [%2]! \n" \ 38 "vmov.u8 d3, d2 \n" \ 39 "vzip.u8 d2, d3 \n" 40 41 // Read 8 Y, 8 U and 8 V from 444 42 #define READYUV444 \ 43 MEMACCESS(0) \ 44 "vld1.8 {d0}, [%0]! \n" \ 45 MEMACCESS(1) \ 46 "vld1.8 {d2}, [%1]! \n" \ 47 MEMACCESS(2) \ 48 "vld1.8 {d3}, [%2]! \n" \ 49 "vpaddl.u8 q1, q1 \n" \ 50 "vrshrn.u16 d2, q1, #1 \n" 51 52 // Read 8 Y, and set 4 U and 4 V to 128 53 #define READYUV400 \ 54 MEMACCESS(0) \ 55 "vld1.8 {d0}, [%0]! \n" \ 56 "vmov.u8 d2, #128 \n" 57 58 // Read 8 Y and 4 UV from NV12 59 #define READNV12 \ 60 MEMACCESS(0) \ 61 "vld1.8 {d0}, [%0]! \n" \ 62 MEMACCESS(1) \ 63 "vld1.8 {d2}, [%1]! \n" \ 64 "vmov.u8 d3, d2 \n"/* split odd/even uv apart */\ 65 "vuzp.u8 d2, d3 \n" \ 66 "vtrn.u32 d2, d3 \n" 67 68 // Read 8 Y and 4 VU from NV21 69 #define READNV21 \ 70 MEMACCESS(0) \ 71 "vld1.8 {d0}, [%0]! \n" \ 72 MEMACCESS(1) \ 73 "vld1.8 {d2}, [%1]! \n" \ 74 "vmov.u8 d3, d2 \n"/* split odd/even uv apart */\ 75 "vuzp.u8 d3, d2 \n" \ 76 "vtrn.u32 d2, d3 \n" 77 78 // Read 8 YUY2 79 #define READYUY2 \ 80 MEMACCESS(0) \ 81 "vld2.8 {d0, d2}, [%0]! \n" \ 82 "vmov.u8 d3, d2 \n" \ 83 "vuzp.u8 d2, d3 \n" \ 84 "vtrn.u32 d2, d3 \n" 85 86 // Read 8 UYVY 87 #define READUYVY \ 88 MEMACCESS(0) \ 89 "vld2.8 {d2, d3}, [%0]! \n" \ 90 "vmov.u8 d0, d3 \n" \ 91 "vmov.u8 d3, d2 \n" \ 92 "vuzp.u8 d2, d3 \n" \ 93 "vtrn.u32 d2, d3 \n" 94 95 #define YUV422TORGB \ 96 "veor.u8 d2, d26 \n"/*subtract 128 from u and v*/\ 97 "vmull.s8 q8, d2, d24 \n"/* u/v B/R component */\ 98 "vmull.s8 q9, d2, d25 \n"/* u/v G component */\ 99 "vmov.u8 d1, #0 \n"/* split odd/even y apart */\ 100 "vtrn.u8 d0, d1 \n" \ 101 "vsub.s16 q0, q0, q15 \n"/* offset y */\ 102 "vmul.s16 q0, q0, q14 \n" \ 103 "vadd.s16 d18, d19 \n" \ 104 "vqadd.s16 d20, d0, d16 \n" /* B */ \ 105 "vqadd.s16 d21, d1, d16 \n" \ 106 "vqadd.s16 d22, d0, d17 \n" /* R */ \ 107 "vqadd.s16 d23, d1, d17 \n" \ 108 "vqadd.s16 d16, d0, d18 \n" /* G */ \ 109 "vqadd.s16 d17, d1, d18 \n" \ 110 "vqshrun.s16 d0, q10, #6 \n" /* B */ \ 111 "vqshrun.s16 d1, q11, #6 \n" /* G */ \ 112 "vqshrun.s16 d2, q8, #6 \n" /* R */ \ 113 "vmovl.u8 q10, d0 \n"/* set up for reinterleave*/\ 114 "vmovl.u8 q11, d1 \n" \ 115 "vmovl.u8 q8, d2 \n" \ 116 "vtrn.u8 d20, d21 \n" \ 117 "vtrn.u8 d22, d23 \n" \ 118 "vtrn.u8 d16, d17 \n" \ 119 "vmov.u8 d21, d16 \n" 120 121 static vec8 kUVToRB = { 127, 127, 127, 127, 102, 102, 102, 102, 122 0, 0, 0, 0, 0, 0, 0, 0 }; 123 static vec8 kUVToG = { -25, -25, -25, -25, -52, -52, -52, -52, 124 0, 0, 0, 0, 0, 0, 0, 0 }; 125 126 void I444ToARGBRow_NEON(const uint8* src_y, 127 const uint8* src_u, 128 const uint8* src_v, 129 uint8* dst_argb, 130 int width) { 131 asm volatile ( 132 MEMACCESS(5) 133 "vld1.8 {d24}, [%5] \n" 134 MEMACCESS(6) 135 "vld1.8 {d25}, [%6] \n" 136 "vmov.u8 d26, #128 \n" 137 "vmov.u16 q14, #74 \n" 138 "vmov.u16 q15, #16 \n" 139 ".p2align 2 \n" 140 "1: \n" 141 READYUV444 142 YUV422TORGB 143 "subs %4, %4, #8 \n" 144 "vmov.u8 d23, #255 \n" 145 MEMACCESS(3) 146 "vst4.8 {d20, d21, d22, d23}, [%3]! \n" 147 "bgt 1b \n" 148 : "+r"(src_y), // %0 149 "+r"(src_u), // %1 150 "+r"(src_v), // %2 151 "+r"(dst_argb), // %3 152 "+r"(width) // %4 153 : "r"(&kUVToRB), // %5 154 "r"(&kUVToG) // %6 155 : "cc", "memory", "q0", "q1", "q2", "q3", 156 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 157 ); 158 } 159 160 void I422ToARGBRow_NEON(const uint8* src_y, 161 const uint8* src_u, 162 const uint8* src_v, 163 uint8* dst_argb, 164 int width) { 165 asm volatile ( 166 MEMACCESS(5) 167 "vld1.8 {d24}, [%5] \n" 168 MEMACCESS(6) 169 "vld1.8 {d25}, [%6] \n" 170 "vmov.u8 d26, #128 \n" 171 "vmov.u16 q14, #74 \n" 172 "vmov.u16 q15, #16 \n" 173 ".p2align 2 \n" 174 "1: \n" 175 READYUV422 176 YUV422TORGB 177 "subs %4, %4, #8 \n" 178 "vmov.u8 d23, #255 \n" 179 MEMACCESS(3) 180 "vst4.8 {d20, d21, d22, d23}, [%3]! \n" 181 "bgt 1b \n" 182 : "+r"(src_y), // %0 183 "+r"(src_u), // %1 184 "+r"(src_v), // %2 185 "+r"(dst_argb), // %3 186 "+r"(width) // %4 187 : "r"(&kUVToRB), // %5 188 "r"(&kUVToG) // %6 189 : "cc", "memory", "q0", "q1", "q2", "q3", 190 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 191 ); 192 } 193 194 void I411ToARGBRow_NEON(const uint8* src_y, 195 const uint8* src_u, 196 const uint8* src_v, 197 uint8* dst_argb, 198 int width) { 199 asm volatile ( 200 MEMACCESS(5) 201 "vld1.8 {d24}, [%5] \n" 202 MEMACCESS(6) 203 "vld1.8 {d25}, [%6] \n" 204 "vmov.u8 d26, #128 \n" 205 "vmov.u16 q14, #74 \n" 206 "vmov.u16 q15, #16 \n" 207 ".p2align 2 \n" 208 "1: \n" 209 READYUV411 210 YUV422TORGB 211 "subs %4, %4, #8 \n" 212 "vmov.u8 d23, #255 \n" 213 MEMACCESS(3) 214 "vst4.8 {d20, d21, d22, d23}, [%3]! \n" 215 "bgt 1b \n" 216 : "+r"(src_y), // %0 217 "+r"(src_u), // %1 218 "+r"(src_v), // %2 219 "+r"(dst_argb), // %3 220 "+r"(width) // %4 221 : "r"(&kUVToRB), // %5 222 "r"(&kUVToG) // %6 223 : "cc", "memory", "q0", "q1", "q2", "q3", 224 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 225 ); 226 } 227 228 void I422ToBGRARow_NEON(const uint8* src_y, 229 const uint8* src_u, 230 const uint8* src_v, 231 uint8* dst_bgra, 232 int width) { 233 asm volatile ( 234 MEMACCESS(5) 235 "vld1.8 {d24}, [%5] \n" 236 MEMACCESS(6) 237 "vld1.8 {d25}, [%6] \n" 238 "vmov.u8 d26, #128 \n" 239 "vmov.u16 q14, #74 \n" 240 "vmov.u16 q15, #16 \n" 241 ".p2align 2 \n" 242 "1: \n" 243 READYUV422 244 YUV422TORGB 245 "subs %4, %4, #8 \n" 246 "vswp.u8 d20, d22 \n" 247 "vmov.u8 d19, #255 \n" 248 MEMACCESS(3) 249 "vst4.8 {d19, d20, d21, d22}, [%3]! \n" 250 "bgt 1b \n" 251 : "+r"(src_y), // %0 252 "+r"(src_u), // %1 253 "+r"(src_v), // %2 254 "+r"(dst_bgra), // %3 255 "+r"(width) // %4 256 : "r"(&kUVToRB), // %5 257 "r"(&kUVToG) // %6 258 : "cc", "memory", "q0", "q1", "q2", "q3", 259 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 260 ); 261 } 262 263 void I422ToABGRRow_NEON(const uint8* src_y, 264 const uint8* src_u, 265 const uint8* src_v, 266 uint8* dst_abgr, 267 int width) { 268 asm volatile ( 269 MEMACCESS(5) 270 "vld1.8 {d24}, [%5] \n" 271 MEMACCESS(6) 272 "vld1.8 {d25}, [%6] \n" 273 "vmov.u8 d26, #128 \n" 274 "vmov.u16 q14, #74 \n" 275 "vmov.u16 q15, #16 \n" 276 ".p2align 2 \n" 277 "1: \n" 278 READYUV422 279 YUV422TORGB 280 "subs %4, %4, #8 \n" 281 "vswp.u8 d20, d22 \n" 282 "vmov.u8 d23, #255 \n" 283 MEMACCESS(3) 284 "vst4.8 {d20, d21, d22, d23}, [%3]! \n" 285 "bgt 1b \n" 286 : "+r"(src_y), // %0 287 "+r"(src_u), // %1 288 "+r"(src_v), // %2 289 "+r"(dst_abgr), // %3 290 "+r"(width) // %4 291 : "r"(&kUVToRB), // %5 292 "r"(&kUVToG) // %6 293 : "cc", "memory", "q0", "q1", "q2", "q3", 294 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 295 ); 296 } 297 298 void I422ToRGBARow_NEON(const uint8* src_y, 299 const uint8* src_u, 300 const uint8* src_v, 301 uint8* dst_rgba, 302 int width) { 303 asm volatile ( 304 MEMACCESS(5) 305 "vld1.8 {d24}, [%5] \n" 306 MEMACCESS(6) 307 "vld1.8 {d25}, [%6] \n" 308 "vmov.u8 d26, #128 \n" 309 "vmov.u16 q14, #74 \n" 310 "vmov.u16 q15, #16 \n" 311 ".p2align 2 \n" 312 "1: \n" 313 READYUV422 314 YUV422TORGB 315 "subs %4, %4, #8 \n" 316 "vmov.u8 d19, #255 \n" 317 MEMACCESS(3) 318 "vst4.8 {d19, d20, d21, d22}, [%3]! \n" 319 "bgt 1b \n" 320 : "+r"(src_y), // %0 321 "+r"(src_u), // %1 322 "+r"(src_v), // %2 323 "+r"(dst_rgba), // %3 324 "+r"(width) // %4 325 : "r"(&kUVToRB), // %5 326 "r"(&kUVToG) // %6 327 : "cc", "memory", "q0", "q1", "q2", "q3", 328 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 329 ); 330 } 331 332 void I422ToRGB24Row_NEON(const uint8* src_y, 333 const uint8* src_u, 334 const uint8* src_v, 335 uint8* dst_rgb24, 336 int width) { 337 asm volatile ( 338 MEMACCESS(5) 339 "vld1.8 {d24}, [%5] \n" 340 MEMACCESS(6) 341 "vld1.8 {d25}, [%6] \n" 342 "vmov.u8 d26, #128 \n" 343 "vmov.u16 q14, #74 \n" 344 "vmov.u16 q15, #16 \n" 345 ".p2align 2 \n" 346 "1: \n" 347 READYUV422 348 YUV422TORGB 349 "subs %4, %4, #8 \n" 350 MEMACCESS(3) 351 "vst3.8 {d20, d21, d22}, [%3]! \n" 352 "bgt 1b \n" 353 : "+r"(src_y), // %0 354 "+r"(src_u), // %1 355 "+r"(src_v), // %2 356 "+r"(dst_rgb24), // %3 357 "+r"(width) // %4 358 : "r"(&kUVToRB), // %5 359 "r"(&kUVToG) // %6 360 : "cc", "memory", "q0", "q1", "q2", "q3", 361 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 362 ); 363 } 364 365 void I422ToRAWRow_NEON(const uint8* src_y, 366 const uint8* src_u, 367 const uint8* src_v, 368 uint8* dst_raw, 369 int width) { 370 asm volatile ( 371 MEMACCESS(5) 372 "vld1.8 {d24}, [%5] \n" 373 MEMACCESS(6) 374 "vld1.8 {d25}, [%6] \n" 375 "vmov.u8 d26, #128 \n" 376 "vmov.u16 q14, #74 \n" 377 "vmov.u16 q15, #16 \n" 378 ".p2align 2 \n" 379 "1: \n" 380 READYUV422 381 YUV422TORGB 382 "subs %4, %4, #8 \n" 383 "vswp.u8 d20, d22 \n" 384 MEMACCESS(3) 385 "vst3.8 {d20, d21, d22}, [%3]! \n" 386 "bgt 1b \n" 387 : "+r"(src_y), // %0 388 "+r"(src_u), // %1 389 "+r"(src_v), // %2 390 "+r"(dst_raw), // %3 391 "+r"(width) // %4 392 : "r"(&kUVToRB), // %5 393 "r"(&kUVToG) // %6 394 : "cc", "memory", "q0", "q1", "q2", "q3", 395 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 396 ); 397 } 398 399 #define ARGBTORGB565 \ 400 "vshr.u8 d20, d20, #3 \n" /* B */ \ 401 "vshr.u8 d21, d21, #2 \n" /* G */ \ 402 "vshr.u8 d22, d22, #3 \n" /* R */ \ 403 "vmovl.u8 q8, d20 \n" /* B */ \ 404 "vmovl.u8 q9, d21 \n" /* G */ \ 405 "vmovl.u8 q10, d22 \n" /* R */ \ 406 "vshl.u16 q9, q9, #5 \n" /* G */ \ 407 "vshl.u16 q10, q10, #11 \n" /* R */ \ 408 "vorr q0, q8, q9 \n" /* BG */ \ 409 "vorr q0, q0, q10 \n" /* BGR */ 410 411 void I422ToRGB565Row_NEON(const uint8* src_y, 412 const uint8* src_u, 413 const uint8* src_v, 414 uint8* dst_rgb565, 415 int width) { 416 asm volatile ( 417 MEMACCESS(5) 418 "vld1.8 {d24}, [%5] \n" 419 MEMACCESS(6) 420 "vld1.8 {d25}, [%6] \n" 421 "vmov.u8 d26, #128 \n" 422 "vmov.u16 q14, #74 \n" 423 "vmov.u16 q15, #16 \n" 424 ".p2align 2 \n" 425 "1: \n" 426 READYUV422 427 YUV422TORGB 428 "subs %4, %4, #8 \n" 429 ARGBTORGB565 430 MEMACCESS(3) 431 "vst1.8 {q0}, [%3]! \n" // store 8 pixels RGB565. 432 "bgt 1b \n" 433 : "+r"(src_y), // %0 434 "+r"(src_u), // %1 435 "+r"(src_v), // %2 436 "+r"(dst_rgb565), // %3 437 "+r"(width) // %4 438 : "r"(&kUVToRB), // %5 439 "r"(&kUVToG) // %6 440 : "cc", "memory", "q0", "q1", "q2", "q3", 441 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 442 ); 443 } 444 445 #define ARGBTOARGB1555 \ 446 "vshr.u8 q10, q10, #3 \n" /* B */ \ 447 "vshr.u8 d22, d22, #3 \n" /* R */ \ 448 "vshr.u8 d23, d23, #7 \n" /* A */ \ 449 "vmovl.u8 q8, d20 \n" /* B */ \ 450 "vmovl.u8 q9, d21 \n" /* G */ \ 451 "vmovl.u8 q10, d22 \n" /* R */ \ 452 "vmovl.u8 q11, d23 \n" /* A */ \ 453 "vshl.u16 q9, q9, #5 \n" /* G */ \ 454 "vshl.u16 q10, q10, #10 \n" /* R */ \ 455 "vshl.u16 q11, q11, #15 \n" /* A */ \ 456 "vorr q0, q8, q9 \n" /* BG */ \ 457 "vorr q1, q10, q11 \n" /* RA */ \ 458 "vorr q0, q0, q1 \n" /* BGRA */ 459 460 void I422ToARGB1555Row_NEON(const uint8* src_y, 461 const uint8* src_u, 462 const uint8* src_v, 463 uint8* dst_argb1555, 464 int width) { 465 asm volatile ( 466 MEMACCESS(5) 467 "vld1.8 {d24}, [%5] \n" 468 MEMACCESS(6) 469 "vld1.8 {d25}, [%6] \n" 470 "vmov.u8 d26, #128 \n" 471 "vmov.u16 q14, #74 \n" 472 "vmov.u16 q15, #16 \n" 473 ".p2align 2 \n" 474 "1: \n" 475 READYUV422 476 YUV422TORGB 477 "subs %4, %4, #8 \n" 478 "vmov.u8 d23, #255 \n" 479 ARGBTOARGB1555 480 MEMACCESS(3) 481 "vst1.8 {q0}, [%3]! \n" // store 8 pixels ARGB1555. 482 "bgt 1b \n" 483 : "+r"(src_y), // %0 484 "+r"(src_u), // %1 485 "+r"(src_v), // %2 486 "+r"(dst_argb1555), // %3 487 "+r"(width) // %4 488 : "r"(&kUVToRB), // %5 489 "r"(&kUVToG) // %6 490 : "cc", "memory", "q0", "q1", "q2", "q3", 491 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 492 ); 493 } 494 495 #define ARGBTOARGB4444 \ 496 "vshr.u8 d20, d20, #4 \n" /* B */ \ 497 "vbic.32 d21, d21, d4 \n" /* G */ \ 498 "vshr.u8 d22, d22, #4 \n" /* R */ \ 499 "vbic.32 d23, d23, d4 \n" /* A */ \ 500 "vorr d0, d20, d21 \n" /* BG */ \ 501 "vorr d1, d22, d23 \n" /* RA */ \ 502 "vzip.u8 d0, d1 \n" /* BGRA */ 503 504 void I422ToARGB4444Row_NEON(const uint8* src_y, 505 const uint8* src_u, 506 const uint8* src_v, 507 uint8* dst_argb4444, 508 int width) { 509 asm volatile ( 510 MEMACCESS(5) 511 "vld1.8 {d24}, [%5] \n" 512 MEMACCESS(6) 513 "vld1.8 {d25}, [%6] \n" 514 "vmov.u8 d26, #128 \n" 515 "vmov.u16 q14, #74 \n" 516 "vmov.u16 q15, #16 \n" 517 "vmov.u8 d4, #0x0f \n" // bits to clear with vbic. 518 ".p2align 2 \n" 519 "1: \n" 520 READYUV422 521 YUV422TORGB 522 "subs %4, %4, #8 \n" 523 "vmov.u8 d23, #255 \n" 524 ARGBTOARGB4444 525 MEMACCESS(3) 526 "vst1.8 {q0}, [%3]! \n" // store 8 pixels ARGB4444. 527 "bgt 1b \n" 528 : "+r"(src_y), // %0 529 "+r"(src_u), // %1 530 "+r"(src_v), // %2 531 "+r"(dst_argb4444), // %3 532 "+r"(width) // %4 533 : "r"(&kUVToRB), // %5 534 "r"(&kUVToG) // %6 535 : "cc", "memory", "q0", "q1", "q2", "q3", 536 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 537 ); 538 } 539 540 void YToARGBRow_NEON(const uint8* src_y, 541 uint8* dst_argb, 542 int width) { 543 asm volatile ( 544 MEMACCESS(3) 545 MEMACCESS(3) 546 "vld1.8 {d24}, [%3] \n" 547 MEMACCESS(4) 548 "vld1.8 {d25}, [%4] \n" 549 "vmov.u8 d26, #128 \n" 550 "vmov.u16 q14, #74 \n" 551 "vmov.u16 q15, #16 \n" 552 ".p2align 2 \n" 553 "1: \n" 554 READYUV400 555 YUV422TORGB 556 "subs %2, %2, #8 \n" 557 "vmov.u8 d23, #255 \n" 558 MEMACCESS(1) 559 "vst4.8 {d20, d21, d22, d23}, [%1]! \n" 560 "bgt 1b \n" 561 : "+r"(src_y), // %0 562 "+r"(dst_argb), // %1 563 "+r"(width) // %2 564 : "r"(&kUVToRB), // %3 565 "r"(&kUVToG) // %4 566 : "cc", "memory", "q0", "q1", "q2", "q3", 567 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 568 ); 569 } 570 571 void I400ToARGBRow_NEON(const uint8* src_y, 572 uint8* dst_argb, 573 int width) { 574 asm volatile ( 575 ".p2align 2 \n" 576 "vmov.u8 d23, #255 \n" 577 "1: \n" 578 MEMACCESS(0) 579 "vld1.8 {d20}, [%0]! \n" 580 "vmov d21, d20 \n" 581 "vmov d22, d20 \n" 582 "subs %2, %2, #8 \n" 583 MEMACCESS(1) 584 "vst4.8 {d20, d21, d22, d23}, [%1]! \n" 585 "bgt 1b \n" 586 : "+r"(src_y), // %0 587 "+r"(dst_argb), // %1 588 "+r"(width) // %2 589 : 590 : "cc", "memory", "d20", "d21", "d22", "d23" 591 ); 592 } 593 594 void NV12ToARGBRow_NEON(const uint8* src_y, 595 const uint8* src_uv, 596 uint8* dst_argb, 597 int width) { 598 asm volatile ( 599 MEMACCESS(4) 600 "vld1.8 {d24}, [%4] \n" 601 MEMACCESS(5) 602 "vld1.8 {d25}, [%5] \n" 603 "vmov.u8 d26, #128 \n" 604 "vmov.u16 q14, #74 \n" 605 "vmov.u16 q15, #16 \n" 606 ".p2align 2 \n" 607 "1: \n" 608 READNV12 609 YUV422TORGB 610 "subs %3, %3, #8 \n" 611 "vmov.u8 d23, #255 \n" 612 MEMACCESS(2) 613 "vst4.8 {d20, d21, d22, d23}, [%2]! \n" 614 "bgt 1b \n" 615 : "+r"(src_y), // %0 616 "+r"(src_uv), // %1 617 "+r"(dst_argb), // %2 618 "+r"(width) // %3 619 : "r"(&kUVToRB), // %4 620 "r"(&kUVToG) // %5 621 : "cc", "memory", "q0", "q1", "q2", "q3", 622 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 623 ); 624 } 625 626 void NV21ToARGBRow_NEON(const uint8* src_y, 627 const uint8* src_uv, 628 uint8* dst_argb, 629 int width) { 630 asm volatile ( 631 MEMACCESS(4) 632 "vld1.8 {d24}, [%4] \n" 633 MEMACCESS(5) 634 "vld1.8 {d25}, [%5] \n" 635 "vmov.u8 d26, #128 \n" 636 "vmov.u16 q14, #74 \n" 637 "vmov.u16 q15, #16 \n" 638 ".p2align 2 \n" 639 "1: \n" 640 READNV21 641 YUV422TORGB 642 "subs %3, %3, #8 \n" 643 "vmov.u8 d23, #255 \n" 644 MEMACCESS(2) 645 "vst4.8 {d20, d21, d22, d23}, [%2]! \n" 646 "bgt 1b \n" 647 : "+r"(src_y), // %0 648 "+r"(src_uv), // %1 649 "+r"(dst_argb), // %2 650 "+r"(width) // %3 651 : "r"(&kUVToRB), // %4 652 "r"(&kUVToG) // %5 653 : "cc", "memory", "q0", "q1", "q2", "q3", 654 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 655 ); 656 } 657 658 void NV12ToRGB565Row_NEON(const uint8* src_y, 659 const uint8* src_uv, 660 uint8* dst_rgb565, 661 int width) { 662 asm volatile ( 663 MEMACCESS(4) 664 "vld1.8 {d24}, [%4] \n" 665 MEMACCESS(5) 666 "vld1.8 {d25}, [%5] \n" 667 "vmov.u8 d26, #128 \n" 668 "vmov.u16 q14, #74 \n" 669 "vmov.u16 q15, #16 \n" 670 ".p2align 2 \n" 671 "1: \n" 672 READNV12 673 YUV422TORGB 674 "subs %3, %3, #8 \n" 675 ARGBTORGB565 676 MEMACCESS(2) 677 "vst1.8 {q0}, [%2]! \n" // store 8 pixels RGB565. 678 "bgt 1b \n" 679 : "+r"(src_y), // %0 680 "+r"(src_uv), // %1 681 "+r"(dst_rgb565), // %2 682 "+r"(width) // %3 683 : "r"(&kUVToRB), // %4 684 "r"(&kUVToG) // %5 685 : "cc", "memory", "q0", "q1", "q2", "q3", 686 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 687 ); 688 } 689 690 void NV21ToRGB565Row_NEON(const uint8* src_y, 691 const uint8* src_uv, 692 uint8* dst_rgb565, 693 int width) { 694 asm volatile ( 695 MEMACCESS(4) 696 "vld1.8 {d24}, [%4] \n" 697 MEMACCESS(5) 698 "vld1.8 {d25}, [%5] \n" 699 "vmov.u8 d26, #128 \n" 700 "vmov.u16 q14, #74 \n" 701 "vmov.u16 q15, #16 \n" 702 ".p2align 2 \n" 703 "1: \n" 704 READNV21 705 YUV422TORGB 706 "subs %3, %3, #8 \n" 707 ARGBTORGB565 708 MEMACCESS(2) 709 "vst1.8 {q0}, [%2]! \n" // store 8 pixels RGB565. 710 "bgt 1b \n" 711 : "+r"(src_y), // %0 712 "+r"(src_uv), // %1 713 "+r"(dst_rgb565), // %2 714 "+r"(width) // %3 715 : "r"(&kUVToRB), // %4 716 "r"(&kUVToG) // %5 717 : "cc", "memory", "q0", "q1", "q2", "q3", 718 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 719 ); 720 } 721 722 void YUY2ToARGBRow_NEON(const uint8* src_yuy2, 723 uint8* dst_argb, 724 int width) { 725 asm volatile ( 726 MEMACCESS(3) 727 "vld1.8 {d24}, [%3] \n" 728 MEMACCESS(4) 729 "vld1.8 {d25}, [%4] \n" 730 "vmov.u8 d26, #128 \n" 731 "vmov.u16 q14, #74 \n" 732 "vmov.u16 q15, #16 \n" 733 ".p2align 2 \n" 734 "1: \n" 735 READYUY2 736 YUV422TORGB 737 "subs %2, %2, #8 \n" 738 "vmov.u8 d23, #255 \n" 739 MEMACCESS(1) 740 "vst4.8 {d20, d21, d22, d23}, [%1]! \n" 741 "bgt 1b \n" 742 : "+r"(src_yuy2), // %0 743 "+r"(dst_argb), // %1 744 "+r"(width) // %2 745 : "r"(&kUVToRB), // %3 746 "r"(&kUVToG) // %4 747 : "cc", "memory", "q0", "q1", "q2", "q3", 748 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 749 ); 750 } 751 752 void UYVYToARGBRow_NEON(const uint8* src_uyvy, 753 uint8* dst_argb, 754 int width) { 755 asm volatile ( 756 MEMACCESS(3) 757 "vld1.8 {d24}, [%3] \n" 758 MEMACCESS(4) 759 "vld1.8 {d25}, [%4] \n" 760 "vmov.u8 d26, #128 \n" 761 "vmov.u16 q14, #74 \n" 762 "vmov.u16 q15, #16 \n" 763 ".p2align 2 \n" 764 "1: \n" 765 READUYVY 766 YUV422TORGB 767 "subs %2, %2, #8 \n" 768 "vmov.u8 d23, #255 \n" 769 MEMACCESS(1) 770 "vst4.8 {d20, d21, d22, d23}, [%1]! \n" 771 "bgt 1b \n" 772 : "+r"(src_uyvy), // %0 773 "+r"(dst_argb), // %1 774 "+r"(width) // %2 775 : "r"(&kUVToRB), // %3 776 "r"(&kUVToG) // %4 777 : "cc", "memory", "q0", "q1", "q2", "q3", 778 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 779 ); 780 } 781 782 // Reads 16 pairs of UV and write even values to dst_u and odd to dst_v. 783 void SplitUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v, 784 int width) { 785 asm volatile ( 786 ".p2align 2 \n" 787 "1: \n" 788 MEMACCESS(0) 789 "vld2.8 {q0, q1}, [%0]! \n" // load 16 pairs of UV 790 "subs %3, %3, #16 \n" // 16 processed per loop 791 MEMACCESS(1) 792 "vst1.8 {q0}, [%1]! \n" // store U 793 MEMACCESS(2) 794 "vst1.8 {q1}, [%2]! \n" // store V 795 "bgt 1b \n" 796 : "+r"(src_uv), // %0 797 "+r"(dst_u), // %1 798 "+r"(dst_v), // %2 799 "+r"(width) // %3 // Output registers 800 : // Input registers 801 : "cc", "memory", "q0", "q1" // Clobber List 802 ); 803 } 804 805 // Reads 16 U's and V's and writes out 16 pairs of UV. 806 void MergeUVRow_NEON(const uint8* src_u, const uint8* src_v, uint8* dst_uv, 807 int width) { 808 asm volatile ( 809 ".p2align 2 \n" 810 "1: \n" 811 MEMACCESS(0) 812 "vld1.8 {q0}, [%0]! \n" // load U 813 MEMACCESS(1) 814 "vld1.8 {q1}, [%1]! \n" // load V 815 "subs %3, %3, #16 \n" // 16 processed per loop 816 MEMACCESS(2) 817 "vst2.u8 {q0, q1}, [%2]! \n" // store 16 pairs of UV 818 "bgt 1b \n" 819 : 820 "+r"(src_u), // %0 821 "+r"(src_v), // %1 822 "+r"(dst_uv), // %2 823 "+r"(width) // %3 // Output registers 824 : // Input registers 825 : "cc", "memory", "q0", "q1" // Clobber List 826 ); 827 } 828 829 // Copy multiple of 32. vld4.8 allow unaligned and is fastest on a15. 830 void CopyRow_NEON(const uint8* src, uint8* dst, int count) { 831 asm volatile ( 832 ".p2align 2 \n" 833 "1: \n" 834 MEMACCESS(0) 835 "vld1.8 {d0, d1, d2, d3}, [%0]! \n" // load 32 836 "subs %2, %2, #32 \n" // 32 processed per loop 837 MEMACCESS(1) 838 "vst1.8 {d0, d1, d2, d3}, [%1]! \n" // store 32 839 "bgt 1b \n" 840 : "+r"(src), // %0 841 "+r"(dst), // %1 842 "+r"(count) // %2 // Output registers 843 : // Input registers 844 : "cc", "memory", "q0", "q1" // Clobber List 845 ); 846 } 847 848 // SetRow8 writes 'count' bytes using a 32 bit value repeated. 849 void SetRow_NEON(uint8* dst, uint32 v32, int count) { 850 asm volatile ( 851 "vdup.u32 q0, %2 \n" // duplicate 4 ints 852 "1: \n" 853 "subs %1, %1, #16 \n" // 16 bytes per loop 854 MEMACCESS(0) 855 "vst1.8 {q0}, [%0]! \n" // store 856 "bgt 1b \n" 857 : "+r"(dst), // %0 858 "+r"(count) // %1 859 : "r"(v32) // %2 860 : "cc", "memory", "q0" 861 ); 862 } 863 864 // TODO(fbarchard): Make fully assembler 865 // SetRow32 writes 'count' words using a 32 bit value repeated. 866 void ARGBSetRows_NEON(uint8* dst, uint32 v32, int width, 867 int dst_stride, int height) { 868 for (int y = 0; y < height; ++y) { 869 SetRow_NEON(dst, v32, width << 2); 870 dst += dst_stride; 871 } 872 } 873 874 void MirrorRow_NEON(const uint8* src, uint8* dst, int width) { 875 asm volatile ( 876 // Start at end of source row. 877 "mov r3, #-16 \n" 878 "add %0, %0, %2 \n" 879 "sub %0, #16 \n" 880 881 ".p2align 2 \n" 882 "1: \n" 883 MEMACCESS(0) 884 "vld1.8 {q0}, [%0], r3 \n" // src -= 16 885 "subs %2, #16 \n" // 16 pixels per loop. 886 "vrev64.8 q0, q0 \n" 887 MEMACCESS(1) 888 "vst1.8 {d1}, [%1]! \n" // dst += 16 889 MEMACCESS(1) 890 "vst1.8 {d0}, [%1]! \n" 891 "bgt 1b \n" 892 : "+r"(src), // %0 893 "+r"(dst), // %1 894 "+r"(width) // %2 895 : 896 : "cc", "memory", "r3", "q0" 897 ); 898 } 899 900 void MirrorUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v, 901 int width) { 902 asm volatile ( 903 // Start at end of source row. 904 "mov r12, #-16 \n" 905 "add %0, %0, %3, lsl #1 \n" 906 "sub %0, #16 \n" 907 908 ".p2align 2 \n" 909 "1: \n" 910 MEMACCESS(0) 911 "vld2.8 {d0, d1}, [%0], r12 \n" // src -= 16 912 "subs %3, #8 \n" // 8 pixels per loop. 913 "vrev64.8 q0, q0 \n" 914 MEMACCESS(1) 915 "vst1.8 {d0}, [%1]! \n" // dst += 8 916 MEMACCESS(2) 917 "vst1.8 {d1}, [%2]! \n" 918 "bgt 1b \n" 919 : "+r"(src_uv), // %0 920 "+r"(dst_u), // %1 921 "+r"(dst_v), // %2 922 "+r"(width) // %3 923 : 924 : "cc", "memory", "r12", "q0" 925 ); 926 } 927 928 void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width) { 929 asm volatile ( 930 // Start at end of source row. 931 "mov r3, #-16 \n" 932 "add %0, %0, %2, lsl #2 \n" 933 "sub %0, #16 \n" 934 935 ".p2align 2 \n" 936 "1: \n" 937 MEMACCESS(0) 938 "vld1.8 {q0}, [%0], r3 \n" // src -= 16 939 "subs %2, #4 \n" // 4 pixels per loop. 940 "vrev64.32 q0, q0 \n" 941 MEMACCESS(1) 942 "vst1.8 {d1}, [%1]! \n" // dst += 16 943 MEMACCESS(1) 944 "vst1.8 {d0}, [%1]! \n" 945 "bgt 1b \n" 946 : "+r"(src), // %0 947 "+r"(dst), // %1 948 "+r"(width) // %2 949 : 950 : "cc", "memory", "r3", "q0" 951 ); 952 } 953 954 void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix) { 955 asm volatile ( 956 "vmov.u8 d4, #255 \n" // Alpha 957 ".p2align 2 \n" 958 "1: \n" 959 MEMACCESS(0) 960 "vld3.8 {d1, d2, d3}, [%0]! \n" // load 8 pixels of RGB24. 961 "subs %2, %2, #8 \n" // 8 processed per loop. 962 MEMACCESS(1) 963 "vst4.8 {d1, d2, d3, d4}, [%1]! \n" // store 8 pixels of ARGB. 964 "bgt 1b \n" 965 : "+r"(src_rgb24), // %0 966 "+r"(dst_argb), // %1 967 "+r"(pix) // %2 968 : 969 : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List 970 ); 971 } 972 973 void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int pix) { 974 asm volatile ( 975 "vmov.u8 d4, #255 \n" // Alpha 976 ".p2align 2 \n" 977 "1: \n" 978 MEMACCESS(0) 979 "vld3.8 {d1, d2, d3}, [%0]! \n" // load 8 pixels of RAW. 980 "subs %2, %2, #8 \n" // 8 processed per loop. 981 "vswp.u8 d1, d3 \n" // swap R, B 982 MEMACCESS(1) 983 "vst4.8 {d1, d2, d3, d4}, [%1]! \n" // store 8 pixels of ARGB. 984 "bgt 1b \n" 985 : "+r"(src_raw), // %0 986 "+r"(dst_argb), // %1 987 "+r"(pix) // %2 988 : 989 : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List 990 ); 991 } 992 993 #define RGB565TOARGB \ 994 "vshrn.u16 d6, q0, #5 \n" /* G xxGGGGGG */ \ 995 "vuzp.u8 d0, d1 \n" /* d0 xxxBBBBB RRRRRxxx */ \ 996 "vshl.u8 d6, d6, #2 \n" /* G GGGGGG00 upper 6 */ \ 997 "vshr.u8 d1, d1, #3 \n" /* R 000RRRRR lower 5 */ \ 998 "vshl.u8 q0, q0, #3 \n" /* B,R BBBBB000 upper 5 */ \ 999 "vshr.u8 q2, q0, #5 \n" /* B,R 00000BBB lower 3 */ \ 1000 "vorr.u8 d0, d0, d4 \n" /* B */ \ 1001 "vshr.u8 d4, d6, #6 \n" /* G 000000GG lower 2 */ \ 1002 "vorr.u8 d2, d1, d5 \n" /* R */ \ 1003 "vorr.u8 d1, d4, d6 \n" /* G */ 1004 1005 void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int pix) { 1006 asm volatile ( 1007 "vmov.u8 d3, #255 \n" // Alpha 1008 ".p2align 2 \n" 1009 "1: \n" 1010 MEMACCESS(0) 1011 "vld1.8 {q0}, [%0]! \n" // load 8 RGB565 pixels. 1012 "subs %2, %2, #8 \n" // 8 processed per loop. 1013 RGB565TOARGB 1014 MEMACCESS(1) 1015 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB. 1016 "bgt 1b \n" 1017 : "+r"(src_rgb565), // %0 1018 "+r"(dst_argb), // %1 1019 "+r"(pix) // %2 1020 : 1021 : "cc", "memory", "q0", "q1", "q2", "q3" // Clobber List 1022 ); 1023 } 1024 1025 #define ARGB1555TOARGB \ 1026 "vshrn.u16 d7, q0, #8 \n" /* A Arrrrrxx */ \ 1027 "vshr.u8 d6, d7, #2 \n" /* R xxxRRRRR */ \ 1028 "vshrn.u16 d5, q0, #5 \n" /* G xxxGGGGG */ \ 1029 "vmovn.u16 d4, q0 \n" /* B xxxBBBBB */ \ 1030 "vshr.u8 d7, d7, #7 \n" /* A 0000000A */ \ 1031 "vneg.s8 d7, d7 \n" /* A AAAAAAAA upper 8 */ \ 1032 "vshl.u8 d6, d6, #3 \n" /* R RRRRR000 upper 5 */ \ 1033 "vshr.u8 q1, q3, #5 \n" /* R,A 00000RRR lower 3 */ \ 1034 "vshl.u8 q0, q2, #3 \n" /* B,G BBBBB000 upper 5 */ \ 1035 "vshr.u8 q2, q0, #5 \n" /* B,G 00000BBB lower 3 */ \ 1036 "vorr.u8 q1, q1, q3 \n" /* R,A */ \ 1037 "vorr.u8 q0, q0, q2 \n" /* B,G */ \ 1038 1039 // RGB555TOARGB is same as ARGB1555TOARGB but ignores alpha. 1040 #define RGB555TOARGB \ 1041 "vshrn.u16 d6, q0, #5 \n" /* G xxxGGGGG */ \ 1042 "vuzp.u8 d0, d1 \n" /* d0 xxxBBBBB xRRRRRxx */ \ 1043 "vshl.u8 d6, d6, #3 \n" /* G GGGGG000 upper 5 */ \ 1044 "vshr.u8 d1, d1, #2 \n" /* R 00xRRRRR lower 5 */ \ 1045 "vshl.u8 q0, q0, #3 \n" /* B,R BBBBB000 upper 5 */ \ 1046 "vshr.u8 q2, q0, #5 \n" /* B,R 00000BBB lower 3 */ \ 1047 "vorr.u8 d0, d0, d4 \n" /* B */ \ 1048 "vshr.u8 d4, d6, #5 \n" /* G 00000GGG lower 3 */ \ 1049 "vorr.u8 d2, d1, d5 \n" /* R */ \ 1050 "vorr.u8 d1, d4, d6 \n" /* G */ 1051 1052 void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, uint8* dst_argb, 1053 int pix) { 1054 asm volatile ( 1055 "vmov.u8 d3, #255 \n" // Alpha 1056 ".p2align 2 \n" 1057 "1: \n" 1058 MEMACCESS(0) 1059 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB1555 pixels. 1060 "subs %2, %2, #8 \n" // 8 processed per loop. 1061 ARGB1555TOARGB 1062 MEMACCESS(1) 1063 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB. 1064 "bgt 1b \n" 1065 : "+r"(src_argb1555), // %0 1066 "+r"(dst_argb), // %1 1067 "+r"(pix) // %2 1068 : 1069 : "cc", "memory", "q0", "q1", "q2", "q3" // Clobber List 1070 ); 1071 } 1072 1073 #define ARGB4444TOARGB \ 1074 "vuzp.u8 d0, d1 \n" /* d0 BG, d1 RA */ \ 1075 "vshl.u8 q2, q0, #4 \n" /* B,R BBBB0000 */ \ 1076 "vshr.u8 q1, q0, #4 \n" /* G,A 0000GGGG */ \ 1077 "vshr.u8 q0, q2, #4 \n" /* B,R 0000BBBB */ \ 1078 "vorr.u8 q0, q0, q2 \n" /* B,R BBBBBBBB */ \ 1079 "vshl.u8 q2, q1, #4 \n" /* G,A GGGG0000 */ \ 1080 "vorr.u8 q1, q1, q2 \n" /* G,A GGGGGGGG */ \ 1081 "vswp.u8 d1, d2 \n" /* B,R,G,A -> B,G,R,A */ 1082 1083 void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, uint8* dst_argb, 1084 int pix) { 1085 asm volatile ( 1086 "vmov.u8 d3, #255 \n" // Alpha 1087 ".p2align 2 \n" 1088 "1: \n" 1089 MEMACCESS(0) 1090 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB4444 pixels. 1091 "subs %2, %2, #8 \n" // 8 processed per loop. 1092 ARGB4444TOARGB 1093 MEMACCESS(1) 1094 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB. 1095 "bgt 1b \n" 1096 : "+r"(src_argb4444), // %0 1097 "+r"(dst_argb), // %1 1098 "+r"(pix) // %2 1099 : 1100 : "cc", "memory", "q0", "q1", "q2" // Clobber List 1101 ); 1102 } 1103 1104 void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int pix) { 1105 asm volatile ( 1106 ".p2align 2 \n" 1107 "1: \n" 1108 MEMACCESS(0) 1109 "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB. 1110 "subs %2, %2, #8 \n" // 8 processed per loop. 1111 MEMACCESS(1) 1112 "vst3.8 {d1, d2, d3}, [%1]! \n" // store 8 pixels of RGB24. 1113 "bgt 1b \n" 1114 : "+r"(src_argb), // %0 1115 "+r"(dst_rgb24), // %1 1116 "+r"(pix) // %2 1117 : 1118 : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List 1119 ); 1120 } 1121 1122 void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int pix) { 1123 asm volatile ( 1124 ".p2align 2 \n" 1125 "1: \n" 1126 MEMACCESS(0) 1127 "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB. 1128 "subs %2, %2, #8 \n" // 8 processed per loop. 1129 "vswp.u8 d1, d3 \n" // swap R, B 1130 MEMACCESS(1) 1131 "vst3.8 {d1, d2, d3}, [%1]! \n" // store 8 pixels of RAW. 1132 "bgt 1b \n" 1133 : "+r"(src_argb), // %0 1134 "+r"(dst_raw), // %1 1135 "+r"(pix) // %2 1136 : 1137 : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List 1138 ); 1139 } 1140 1141 void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int pix) { 1142 asm volatile ( 1143 ".p2align 2 \n" 1144 "1: \n" 1145 MEMACCESS(0) 1146 "vld2.8 {q0, q1}, [%0]! \n" // load 16 pixels of YUY2. 1147 "subs %2, %2, #16 \n" // 16 processed per loop. 1148 MEMACCESS(1) 1149 "vst1.8 {q0}, [%1]! \n" // store 16 pixels of Y. 1150 "bgt 1b \n" 1151 : "+r"(src_yuy2), // %0 1152 "+r"(dst_y), // %1 1153 "+r"(pix) // %2 1154 : 1155 : "cc", "memory", "q0", "q1" // Clobber List 1156 ); 1157 } 1158 1159 void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int pix) { 1160 asm volatile ( 1161 ".p2align 2 \n" 1162 "1: \n" 1163 MEMACCESS(0) 1164 "vld2.8 {q0, q1}, [%0]! \n" // load 16 pixels of UYVY. 1165 "subs %2, %2, #16 \n" // 16 processed per loop. 1166 MEMACCESS(1) 1167 "vst1.8 {q1}, [%1]! \n" // store 16 pixels of Y. 1168 "bgt 1b \n" 1169 : "+r"(src_uyvy), // %0 1170 "+r"(dst_y), // %1 1171 "+r"(pix) // %2 1172 : 1173 : "cc", "memory", "q0", "q1" // Clobber List 1174 ); 1175 } 1176 1177 void YUY2ToUV422Row_NEON(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v, 1178 int pix) { 1179 asm volatile ( 1180 ".p2align 2 \n" 1181 "1: \n" 1182 MEMACCESS(0) 1183 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of YUY2. 1184 "subs %3, %3, #16 \n" // 16 pixels = 8 UVs. 1185 MEMACCESS(1) 1186 "vst1.8 {d1}, [%1]! \n" // store 8 U. 1187 MEMACCESS(2) 1188 "vst1.8 {d3}, [%2]! \n" // store 8 V. 1189 "bgt 1b \n" 1190 : "+r"(src_yuy2), // %0 1191 "+r"(dst_u), // %1 1192 "+r"(dst_v), // %2 1193 "+r"(pix) // %3 1194 : 1195 : "cc", "memory", "d0", "d1", "d2", "d3" // Clobber List 1196 ); 1197 } 1198 1199 void UYVYToUV422Row_NEON(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v, 1200 int pix) { 1201 asm volatile ( 1202 ".p2align 2 \n" 1203 "1: \n" 1204 MEMACCESS(0) 1205 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of UYVY. 1206 "subs %3, %3, #16 \n" // 16 pixels = 8 UVs. 1207 MEMACCESS(1) 1208 "vst1.8 {d0}, [%1]! \n" // store 8 U. 1209 MEMACCESS(2) 1210 "vst1.8 {d2}, [%2]! \n" // store 8 V. 1211 "bgt 1b \n" 1212 : "+r"(src_uyvy), // %0 1213 "+r"(dst_u), // %1 1214 "+r"(dst_v), // %2 1215 "+r"(pix) // %3 1216 : 1217 : "cc", "memory", "d0", "d1", "d2", "d3" // Clobber List 1218 ); 1219 } 1220 1221 void YUY2ToUVRow_NEON(const uint8* src_yuy2, int stride_yuy2, 1222 uint8* dst_u, uint8* dst_v, int pix) { 1223 asm volatile ( 1224 "add %1, %0, %1 \n" // stride + src_yuy2 1225 ".p2align 2 \n" 1226 "1: \n" 1227 MEMACCESS(0) 1228 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of YUY2. 1229 "subs %4, %4, #16 \n" // 16 pixels = 8 UVs. 1230 MEMACCESS(1) 1231 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load next row YUY2. 1232 "vrhadd.u8 d1, d1, d5 \n" // average rows of U 1233 "vrhadd.u8 d3, d3, d7 \n" // average rows of V 1234 MEMACCESS(2) 1235 "vst1.8 {d1}, [%2]! \n" // store 8 U. 1236 MEMACCESS(3) 1237 "vst1.8 {d3}, [%3]! \n" // store 8 V. 1238 "bgt 1b \n" 1239 : "+r"(src_yuy2), // %0 1240 "+r"(stride_yuy2), // %1 1241 "+r"(dst_u), // %2 1242 "+r"(dst_v), // %3 1243 "+r"(pix) // %4 1244 : 1245 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7" // Clobber List 1246 ); 1247 } 1248 1249 void UYVYToUVRow_NEON(const uint8* src_uyvy, int stride_uyvy, 1250 uint8* dst_u, uint8* dst_v, int pix) { 1251 asm volatile ( 1252 "add %1, %0, %1 \n" // stride + src_uyvy 1253 ".p2align 2 \n" 1254 "1: \n" 1255 MEMACCESS(0) 1256 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of UYVY. 1257 "subs %4, %4, #16 \n" // 16 pixels = 8 UVs. 1258 MEMACCESS(1) 1259 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load next row UYVY. 1260 "vrhadd.u8 d0, d0, d4 \n" // average rows of U 1261 "vrhadd.u8 d2, d2, d6 \n" // average rows of V 1262 MEMACCESS(2) 1263 "vst1.8 {d0}, [%2]! \n" // store 8 U. 1264 MEMACCESS(3) 1265 "vst1.8 {d2}, [%3]! \n" // store 8 V. 1266 "bgt 1b \n" 1267 : "+r"(src_uyvy), // %0 1268 "+r"(stride_uyvy), // %1 1269 "+r"(dst_u), // %2 1270 "+r"(dst_v), // %3 1271 "+r"(pix) // %4 1272 : 1273 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7" // Clobber List 1274 ); 1275 } 1276 1277 void HalfRow_NEON(const uint8* src_uv, int src_uv_stride, 1278 uint8* dst_uv, int pix) { 1279 asm volatile ( 1280 // change the stride to row 2 pointer 1281 "add %1, %0 \n" 1282 "1: \n" 1283 MEMACCESS(0) 1284 "vld1.8 {q0}, [%0]! \n" // load row 1 16 pixels. 1285 "subs %3, %3, #16 \n" // 16 processed per loop 1286 MEMACCESS(1) 1287 "vld1.8 {q1}, [%1]! \n" // load row 2 16 pixels. 1288 "vrhadd.u8 q0, q1 \n" // average row 1 and 2 1289 MEMACCESS(2) 1290 "vst1.8 {q0}, [%2]! \n" 1291 "bgt 1b \n" 1292 : "+r"(src_uv), // %0 1293 "+r"(src_uv_stride), // %1 1294 "+r"(dst_uv), // %2 1295 "+r"(pix) // %3 1296 : 1297 : "cc", "memory", "q0", "q1" // Clobber List 1298 ); 1299 } 1300 1301 // Select 2 channels from ARGB on alternating pixels. e.g. BGBGBGBG 1302 void ARGBToBayerRow_NEON(const uint8* src_argb, uint8* dst_bayer, 1303 uint32 selector, int pix) { 1304 asm volatile ( 1305 "vmov.u32 d6[0], %3 \n" // selector 1306 "1: \n" 1307 MEMACCESS(0) 1308 "vld1.8 {q0, q1}, [%0]! \n" // load row 8 pixels. 1309 "subs %2, %2, #8 \n" // 8 processed per loop 1310 "vtbl.8 d4, {d0, d1}, d6 \n" // look up 4 pixels 1311 "vtbl.8 d5, {d2, d3}, d6 \n" // look up 4 pixels 1312 "vtrn.u32 d4, d5 \n" // combine 8 pixels 1313 MEMACCESS(1) 1314 "vst1.8 {d4}, [%1]! \n" // store 8. 1315 "bgt 1b \n" 1316 : "+r"(src_argb), // %0 1317 "+r"(dst_bayer), // %1 1318 "+r"(pix) // %2 1319 : "r"(selector) // %3 1320 : "cc", "memory", "q0", "q1", "q2", "q3" // Clobber List 1321 ); 1322 } 1323 1324 // Select G channels from ARGB. e.g. GGGGGGGG 1325 void ARGBToBayerGGRow_NEON(const uint8* src_argb, uint8* dst_bayer, 1326 uint32 /*selector*/, int pix) { 1327 asm volatile ( 1328 "1: \n" 1329 MEMACCESS(0) 1330 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load row 8 pixels. 1331 "subs %2, %2, #8 \n" // 8 processed per loop 1332 MEMACCESS(1) 1333 "vst1.8 {d1}, [%1]! \n" // store 8 G's. 1334 "bgt 1b \n" 1335 : "+r"(src_argb), // %0 1336 "+r"(dst_bayer), // %1 1337 "+r"(pix) // %2 1338 : 1339 : "cc", "memory", "q0", "q1" // Clobber List 1340 ); 1341 } 1342 1343 // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. 1344 void ARGBShuffleRow_NEON(const uint8* src_argb, uint8* dst_argb, 1345 const uint8* shuffler, int pix) { 1346 asm volatile ( 1347 MEMACCESS(3) 1348 "vld1.8 {q2}, [%3] \n" // shuffler 1349 "1: \n" 1350 MEMACCESS(0) 1351 "vld1.8 {q0}, [%0]! \n" // load 4 pixels. 1352 "subs %2, %2, #4 \n" // 4 processed per loop 1353 "vtbl.8 d2, {d0, d1}, d4 \n" // look up 2 first pixels 1354 "vtbl.8 d3, {d0, d1}, d5 \n" // look up 2 next pixels 1355 MEMACCESS(1) 1356 "vst1.8 {q1}, [%1]! \n" // store 4. 1357 "bgt 1b \n" 1358 : "+r"(src_argb), // %0 1359 "+r"(dst_argb), // %1 1360 "+r"(pix) // %2 1361 : "r"(shuffler) // %3 1362 : "cc", "memory", "q0", "q1", "q2" // Clobber List 1363 ); 1364 } 1365 1366 void I422ToYUY2Row_NEON(const uint8* src_y, 1367 const uint8* src_u, 1368 const uint8* src_v, 1369 uint8* dst_yuy2, int width) { 1370 asm volatile ( 1371 ".p2align 2 \n" 1372 "1: \n" 1373 MEMACCESS(0) 1374 "vld2.8 {d0, d2}, [%0]! \n" // load 16 Ys 1375 MEMACCESS(1) 1376 "vld1.8 {d1}, [%1]! \n" // load 8 Us 1377 MEMACCESS(2) 1378 "vld1.8 {d3}, [%2]! \n" // load 8 Vs 1379 "subs %4, %4, #16 \n" // 16 pixels 1380 MEMACCESS(3) 1381 "vst4.8 {d0, d1, d2, d3}, [%3]! \n" // Store 8 YUY2/16 pixels. 1382 "bgt 1b \n" 1383 : "+r"(src_y), // %0 1384 "+r"(src_u), // %1 1385 "+r"(src_v), // %2 1386 "+r"(dst_yuy2), // %3 1387 "+r"(width) // %4 1388 : 1389 : "cc", "memory", "d0", "d1", "d2", "d3" 1390 ); 1391 } 1392 1393 void I422ToUYVYRow_NEON(const uint8* src_y, 1394 const uint8* src_u, 1395 const uint8* src_v, 1396 uint8* dst_uyvy, int width) { 1397 asm volatile ( 1398 ".p2align 2 \n" 1399 "1: \n" 1400 MEMACCESS(0) 1401 "vld2.8 {d1, d3}, [%0]! \n" // load 16 Ys 1402 MEMACCESS(1) 1403 "vld1.8 {d0}, [%1]! \n" // load 8 Us 1404 MEMACCESS(2) 1405 "vld1.8 {d2}, [%2]! \n" // load 8 Vs 1406 "subs %4, %4, #16 \n" // 16 pixels 1407 MEMACCESS(3) 1408 "vst4.8 {d0, d1, d2, d3}, [%3]! \n" // Store 8 UYVY/16 pixels. 1409 "bgt 1b \n" 1410 : "+r"(src_y), // %0 1411 "+r"(src_u), // %1 1412 "+r"(src_v), // %2 1413 "+r"(dst_uyvy), // %3 1414 "+r"(width) // %4 1415 : 1416 : "cc", "memory", "d0", "d1", "d2", "d3" 1417 ); 1418 } 1419 1420 void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb565, int pix) { 1421 asm volatile ( 1422 ".p2align 2 \n" 1423 "1: \n" 1424 MEMACCESS(0) 1425 "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB. 1426 "subs %2, %2, #8 \n" // 8 processed per loop. 1427 ARGBTORGB565 1428 MEMACCESS(1) 1429 "vst1.8 {q0}, [%1]! \n" // store 8 pixels RGB565. 1430 "bgt 1b \n" 1431 : "+r"(src_argb), // %0 1432 "+r"(dst_rgb565), // %1 1433 "+r"(pix) // %2 1434 : 1435 : "cc", "memory", "q0", "q8", "q9", "q10", "q11" 1436 ); 1437 } 1438 1439 void ARGBToARGB1555Row_NEON(const uint8* src_argb, uint8* dst_argb1555, 1440 int pix) { 1441 asm volatile ( 1442 ".p2align 2 \n" 1443 "1: \n" 1444 MEMACCESS(0) 1445 "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB. 1446 "subs %2, %2, #8 \n" // 8 processed per loop. 1447 ARGBTOARGB1555 1448 MEMACCESS(1) 1449 "vst1.8 {q0}, [%1]! \n" // store 8 pixels ARGB1555. 1450 "bgt 1b \n" 1451 : "+r"(src_argb), // %0 1452 "+r"(dst_argb1555), // %1 1453 "+r"(pix) // %2 1454 : 1455 : "cc", "memory", "q0", "q8", "q9", "q10", "q11" 1456 ); 1457 } 1458 1459 void ARGBToARGB4444Row_NEON(const uint8* src_argb, uint8* dst_argb4444, 1460 int pix) { 1461 asm volatile ( 1462 "vmov.u8 d4, #0x0f \n" // bits to clear with vbic. 1463 ".p2align 2 \n" 1464 "1: \n" 1465 MEMACCESS(0) 1466 "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB. 1467 "subs %2, %2, #8 \n" // 8 processed per loop. 1468 ARGBTOARGB4444 1469 MEMACCESS(1) 1470 "vst1.8 {q0}, [%1]! \n" // store 8 pixels ARGB4444. 1471 "bgt 1b \n" 1472 : "+r"(src_argb), // %0 1473 "+r"(dst_argb4444), // %1 1474 "+r"(pix) // %2 1475 : 1476 : "cc", "memory", "q0", "q8", "q9", "q10", "q11" 1477 ); 1478 } 1479 1480 void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) { 1481 asm volatile ( 1482 "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient 1483 "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient 1484 "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient 1485 "vmov.u8 d27, #16 \n" // Add 16 constant 1486 ".p2align 2 \n" 1487 "1: \n" 1488 MEMACCESS(0) 1489 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels. 1490 "subs %2, %2, #8 \n" // 8 processed per loop. 1491 "vmull.u8 q2, d0, d24 \n" // B 1492 "vmlal.u8 q2, d1, d25 \n" // G 1493 "vmlal.u8 q2, d2, d26 \n" // R 1494 "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y 1495 "vqadd.u8 d0, d27 \n" 1496 MEMACCESS(1) 1497 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 1498 "bgt 1b \n" 1499 : "+r"(src_argb), // %0 1500 "+r"(dst_y), // %1 1501 "+r"(pix) // %2 1502 : 1503 : "cc", "memory", "q0", "q1", "q2", "q12", "q13" 1504 ); 1505 } 1506 1507 void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) { 1508 asm volatile ( 1509 "vmov.u8 d24, #15 \n" // B * 0.11400 coefficient 1510 "vmov.u8 d25, #75 \n" // G * 0.58700 coefficient 1511 "vmov.u8 d26, #38 \n" // R * 0.29900 coefficient 1512 ".p2align 2 \n" 1513 "1: \n" 1514 MEMACCESS(0) 1515 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels. 1516 "subs %2, %2, #8 \n" // 8 processed per loop. 1517 "vmull.u8 q2, d0, d24 \n" // B 1518 "vmlal.u8 q2, d1, d25 \n" // G 1519 "vmlal.u8 q2, d2, d26 \n" // R 1520 "vqrshrun.s16 d0, q2, #7 \n" // 15 bit to 8 bit Y 1521 MEMACCESS(1) 1522 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 1523 "bgt 1b \n" 1524 : "+r"(src_argb), // %0 1525 "+r"(dst_y), // %1 1526 "+r"(pix) // %2 1527 : 1528 : "cc", "memory", "q0", "q1", "q2", "q12", "q13" 1529 ); 1530 } 1531 1532 // 8x1 pixels. 1533 void ARGBToUV444Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v, 1534 int pix) { 1535 asm volatile ( 1536 "vmov.u8 d24, #112 \n" // UB / VR 0.875 coefficient 1537 "vmov.u8 d25, #74 \n" // UG -0.5781 coefficient 1538 "vmov.u8 d26, #38 \n" // UR -0.2969 coefficient 1539 "vmov.u8 d27, #18 \n" // VB -0.1406 coefficient 1540 "vmov.u8 d28, #94 \n" // VG -0.7344 coefficient 1541 "vmov.u16 q15, #0x8080 \n" // 128.5 1542 ".p2align 2 \n" 1543 "1: \n" 1544 MEMACCESS(0) 1545 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels. 1546 "subs %3, %3, #8 \n" // 8 processed per loop. 1547 "vmull.u8 q2, d0, d24 \n" // B 1548 "vmlsl.u8 q2, d1, d25 \n" // G 1549 "vmlsl.u8 q2, d2, d26 \n" // R 1550 "vadd.u16 q2, q2, q15 \n" // +128 -> unsigned 1551 1552 "vmull.u8 q3, d2, d24 \n" // R 1553 "vmlsl.u8 q3, d1, d28 \n" // G 1554 "vmlsl.u8 q3, d0, d27 \n" // B 1555 "vadd.u16 q3, q3, q15 \n" // +128 -> unsigned 1556 1557 "vqshrn.u16 d0, q2, #8 \n" // 16 bit to 8 bit U 1558 "vqshrn.u16 d1, q3, #8 \n" // 16 bit to 8 bit V 1559 1560 MEMACCESS(1) 1561 "vst1.8 {d0}, [%1]! \n" // store 8 pixels U. 1562 MEMACCESS(2) 1563 "vst1.8 {d1}, [%2]! \n" // store 8 pixels V. 1564 "bgt 1b \n" 1565 : "+r"(src_argb), // %0 1566 "+r"(dst_u), // %1 1567 "+r"(dst_v), // %2 1568 "+r"(pix) // %3 1569 : 1570 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q12", "q13", "q14", "q15" 1571 ); 1572 } 1573 1574 // 16x1 pixels -> 8x1. pix is number of argb pixels. e.g. 16. 1575 void ARGBToUV422Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v, 1576 int pix) { 1577 asm volatile ( 1578 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 1579 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 1580 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 1581 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 1582 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 1583 "vmov.u16 q15, #0x8080 \n" // 128.5 1584 ".p2align 2 \n" 1585 "1: \n" 1586 MEMACCESS(0) 1587 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. 1588 MEMACCESS(0) 1589 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels. 1590 1591 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts. 1592 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 1593 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts. 1594 1595 "subs %3, %3, #16 \n" // 16 processed per loop. 1596 "vmul.s16 q8, q0, q10 \n" // B 1597 "vmls.s16 q8, q1, q11 \n" // G 1598 "vmls.s16 q8, q2, q12 \n" // R 1599 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned 1600 1601 "vmul.s16 q9, q2, q10 \n" // R 1602 "vmls.s16 q9, q1, q14 \n" // G 1603 "vmls.s16 q9, q0, q13 \n" // B 1604 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned 1605 1606 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U 1607 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V 1608 1609 MEMACCESS(1) 1610 "vst1.8 {d0}, [%1]! \n" // store 8 pixels U. 1611 MEMACCESS(2) 1612 "vst1.8 {d1}, [%2]! \n" // store 8 pixels V. 1613 "bgt 1b \n" 1614 : "+r"(src_argb), // %0 1615 "+r"(dst_u), // %1 1616 "+r"(dst_v), // %2 1617 "+r"(pix) // %3 1618 : 1619 : "cc", "memory", "q0", "q1", "q2", "q3", 1620 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 1621 ); 1622 } 1623 1624 // 32x1 pixels -> 8x1. pix is number of argb pixels. e.g. 32. 1625 void ARGBToUV411Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v, 1626 int pix) { 1627 asm volatile ( 1628 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 1629 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 1630 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 1631 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 1632 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 1633 "vmov.u16 q15, #0x8080 \n" // 128.5 1634 ".p2align 2 \n" 1635 "1: \n" 1636 MEMACCESS(0) 1637 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. 1638 MEMACCESS(0) 1639 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels. 1640 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts. 1641 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 1642 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts. 1643 MEMACCESS(0) 1644 "vld4.8 {d8, d10, d12, d14}, [%0]! \n" // load 8 more ARGB pixels. 1645 MEMACCESS(0) 1646 "vld4.8 {d9, d11, d13, d15}, [%0]! \n" // load last 8 ARGB pixels. 1647 "vpaddl.u8 q4, q4 \n" // B 16 bytes -> 8 shorts. 1648 "vpaddl.u8 q5, q5 \n" // G 16 bytes -> 8 shorts. 1649 "vpaddl.u8 q6, q6 \n" // R 16 bytes -> 8 shorts. 1650 1651 "vpadd.u16 d0, d0, d1 \n" // B 16 shorts -> 8 shorts. 1652 "vpadd.u16 d1, d8, d9 \n" // B 1653 "vpadd.u16 d2, d2, d3 \n" // G 16 shorts -> 8 shorts. 1654 "vpadd.u16 d3, d10, d11 \n" // G 1655 "vpadd.u16 d4, d4, d5 \n" // R 16 shorts -> 8 shorts. 1656 "vpadd.u16 d5, d12, d13 \n" // R 1657 1658 "vrshr.u16 q0, q0, #1 \n" // 2x average 1659 "vrshr.u16 q1, q1, #1 \n" 1660 "vrshr.u16 q2, q2, #1 \n" 1661 1662 "subs %3, %3, #32 \n" // 32 processed per loop. 1663 "vmul.s16 q8, q0, q10 \n" // B 1664 "vmls.s16 q8, q1, q11 \n" // G 1665 "vmls.s16 q8, q2, q12 \n" // R 1666 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned 1667 "vmul.s16 q9, q2, q10 \n" // R 1668 "vmls.s16 q9, q1, q14 \n" // G 1669 "vmls.s16 q9, q0, q13 \n" // B 1670 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned 1671 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U 1672 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V 1673 MEMACCESS(1) 1674 "vst1.8 {d0}, [%1]! \n" // store 8 pixels U. 1675 MEMACCESS(2) 1676 "vst1.8 {d1}, [%2]! \n" // store 8 pixels V. 1677 "bgt 1b \n" 1678 : "+r"(src_argb), // %0 1679 "+r"(dst_u), // %1 1680 "+r"(dst_v), // %2 1681 "+r"(pix) // %3 1682 : 1683 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 1684 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 1685 ); 1686 } 1687 1688 // 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16. 1689 #define RGBTOUV(QB, QG, QR) \ 1690 "vmul.s16 q8, " #QB ", q10 \n" /* B */ \ 1691 "vmls.s16 q8, " #QG ", q11 \n" /* G */ \ 1692 "vmls.s16 q8, " #QR ", q12 \n" /* R */ \ 1693 "vadd.u16 q8, q8, q15 \n" /* +128 -> unsigned */ \ 1694 "vmul.s16 q9, " #QR ", q10 \n" /* R */ \ 1695 "vmls.s16 q9, " #QG ", q14 \n" /* G */ \ 1696 "vmls.s16 q9, " #QB ", q13 \n" /* B */ \ 1697 "vadd.u16 q9, q9, q15 \n" /* +128 -> unsigned */ \ 1698 "vqshrn.u16 d0, q8, #8 \n" /* 16 bit to 8 bit U */ \ 1699 "vqshrn.u16 d1, q9, #8 \n" /* 16 bit to 8 bit V */ 1700 1701 // TODO(fbarchard): Consider vhadd vertical, then vpaddl horizontal, avoid shr. 1702 void ARGBToUVRow_NEON(const uint8* src_argb, int src_stride_argb, 1703 uint8* dst_u, uint8* dst_v, int pix) { 1704 asm volatile ( 1705 "add %1, %0, %1 \n" // src_stride + src_argb 1706 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 1707 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 1708 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 1709 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 1710 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 1711 "vmov.u16 q15, #0x8080 \n" // 128.5 1712 ".p2align 2 \n" 1713 "1: \n" 1714 MEMACCESS(0) 1715 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. 1716 MEMACCESS(0) 1717 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels. 1718 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts. 1719 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 1720 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts. 1721 MEMACCESS(1) 1722 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more ARGB pixels. 1723 MEMACCESS(1) 1724 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 ARGB pixels. 1725 "vpadal.u8 q0, q4 \n" // B 16 bytes -> 8 shorts. 1726 "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts. 1727 "vpadal.u8 q2, q6 \n" // R 16 bytes -> 8 shorts. 1728 1729 "vrshr.u16 q0, q0, #1 \n" // 2x average 1730 "vrshr.u16 q1, q1, #1 \n" 1731 "vrshr.u16 q2, q2, #1 \n" 1732 1733 "subs %4, %4, #16 \n" // 32 processed per loop. 1734 RGBTOUV(q0, q1, q2) 1735 MEMACCESS(2) 1736 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 1737 MEMACCESS(3) 1738 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 1739 "bgt 1b \n" 1740 : "+r"(src_argb), // %0 1741 "+r"(src_stride_argb), // %1 1742 "+r"(dst_u), // %2 1743 "+r"(dst_v), // %3 1744 "+r"(pix) // %4 1745 : 1746 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 1747 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 1748 ); 1749 } 1750 1751 // TODO(fbarchard): Subsample match C code. 1752 void ARGBToUVJRow_NEON(const uint8* src_argb, int src_stride_argb, 1753 uint8* dst_u, uint8* dst_v, int pix) { 1754 asm volatile ( 1755 "add %1, %0, %1 \n" // src_stride + src_argb 1756 "vmov.s16 q10, #127 / 2 \n" // UB / VR 0.500 coefficient 1757 "vmov.s16 q11, #84 / 2 \n" // UG -0.33126 coefficient 1758 "vmov.s16 q12, #43 / 2 \n" // UR -0.16874 coefficient 1759 "vmov.s16 q13, #20 / 2 \n" // VB -0.08131 coefficient 1760 "vmov.s16 q14, #107 / 2 \n" // VG -0.41869 coefficient 1761 "vmov.u16 q15, #0x8080 \n" // 128.5 1762 ".p2align 2 \n" 1763 "1: \n" 1764 MEMACCESS(0) 1765 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. 1766 MEMACCESS(0) 1767 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels. 1768 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts. 1769 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 1770 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts. 1771 MEMACCESS(1) 1772 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more ARGB pixels. 1773 MEMACCESS(1) 1774 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 ARGB pixels. 1775 "vpadal.u8 q0, q4 \n" // B 16 bytes -> 8 shorts. 1776 "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts. 1777 "vpadal.u8 q2, q6 \n" // R 16 bytes -> 8 shorts. 1778 1779 "vrshr.u16 q0, q0, #1 \n" // 2x average 1780 "vrshr.u16 q1, q1, #1 \n" 1781 "vrshr.u16 q2, q2, #1 \n" 1782 1783 "subs %4, %4, #16 \n" // 32 processed per loop. 1784 RGBTOUV(q0, q1, q2) 1785 MEMACCESS(2) 1786 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 1787 MEMACCESS(3) 1788 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 1789 "bgt 1b \n" 1790 : "+r"(src_argb), // %0 1791 "+r"(src_stride_argb), // %1 1792 "+r"(dst_u), // %2 1793 "+r"(dst_v), // %3 1794 "+r"(pix) // %4 1795 : 1796 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 1797 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 1798 ); 1799 } 1800 1801 void BGRAToUVRow_NEON(const uint8* src_bgra, int src_stride_bgra, 1802 uint8* dst_u, uint8* dst_v, int pix) { 1803 asm volatile ( 1804 "add %1, %0, %1 \n" // src_stride + src_bgra 1805 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 1806 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 1807 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 1808 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 1809 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 1810 "vmov.u16 q15, #0x8080 \n" // 128.5 1811 ".p2align 2 \n" 1812 "1: \n" 1813 MEMACCESS(0) 1814 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 BGRA pixels. 1815 MEMACCESS(0) 1816 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 BGRA pixels. 1817 "vpaddl.u8 q3, q3 \n" // B 16 bytes -> 8 shorts. 1818 "vpaddl.u8 q2, q2 \n" // G 16 bytes -> 8 shorts. 1819 "vpaddl.u8 q1, q1 \n" // R 16 bytes -> 8 shorts. 1820 MEMACCESS(1) 1821 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more BGRA pixels. 1822 MEMACCESS(1) 1823 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 BGRA pixels. 1824 "vpadal.u8 q3, q7 \n" // B 16 bytes -> 8 shorts. 1825 "vpadal.u8 q2, q6 \n" // G 16 bytes -> 8 shorts. 1826 "vpadal.u8 q1, q5 \n" // R 16 bytes -> 8 shorts. 1827 1828 "vrshr.u16 q1, q1, #1 \n" // 2x average 1829 "vrshr.u16 q2, q2, #1 \n" 1830 "vrshr.u16 q3, q3, #1 \n" 1831 1832 "subs %4, %4, #16 \n" // 32 processed per loop. 1833 RGBTOUV(q3, q2, q1) 1834 MEMACCESS(2) 1835 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 1836 MEMACCESS(3) 1837 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 1838 "bgt 1b \n" 1839 : "+r"(src_bgra), // %0 1840 "+r"(src_stride_bgra), // %1 1841 "+r"(dst_u), // %2 1842 "+r"(dst_v), // %3 1843 "+r"(pix) // %4 1844 : 1845 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 1846 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 1847 ); 1848 } 1849 1850 void ABGRToUVRow_NEON(const uint8* src_abgr, int src_stride_abgr, 1851 uint8* dst_u, uint8* dst_v, int pix) { 1852 asm volatile ( 1853 "add %1, %0, %1 \n" // src_stride + src_abgr 1854 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 1855 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 1856 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 1857 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 1858 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 1859 "vmov.u16 q15, #0x8080 \n" // 128.5 1860 ".p2align 2 \n" 1861 "1: \n" 1862 MEMACCESS(0) 1863 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ABGR pixels. 1864 MEMACCESS(0) 1865 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ABGR pixels. 1866 "vpaddl.u8 q2, q2 \n" // B 16 bytes -> 8 shorts. 1867 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 1868 "vpaddl.u8 q0, q0 \n" // R 16 bytes -> 8 shorts. 1869 MEMACCESS(1) 1870 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more ABGR pixels. 1871 MEMACCESS(1) 1872 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 ABGR pixels. 1873 "vpadal.u8 q2, q6 \n" // B 16 bytes -> 8 shorts. 1874 "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts. 1875 "vpadal.u8 q0, q4 \n" // R 16 bytes -> 8 shorts. 1876 1877 "vrshr.u16 q0, q0, #1 \n" // 2x average 1878 "vrshr.u16 q1, q1, #1 \n" 1879 "vrshr.u16 q2, q2, #1 \n" 1880 1881 "subs %4, %4, #16 \n" // 32 processed per loop. 1882 RGBTOUV(q2, q1, q0) 1883 MEMACCESS(2) 1884 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 1885 MEMACCESS(3) 1886 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 1887 "bgt 1b \n" 1888 : "+r"(src_abgr), // %0 1889 "+r"(src_stride_abgr), // %1 1890 "+r"(dst_u), // %2 1891 "+r"(dst_v), // %3 1892 "+r"(pix) // %4 1893 : 1894 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 1895 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 1896 ); 1897 } 1898 1899 void RGBAToUVRow_NEON(const uint8* src_rgba, int src_stride_rgba, 1900 uint8* dst_u, uint8* dst_v, int pix) { 1901 asm volatile ( 1902 "add %1, %0, %1 \n" // src_stride + src_rgba 1903 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 1904 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 1905 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 1906 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 1907 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 1908 "vmov.u16 q15, #0x8080 \n" // 128.5 1909 ".p2align 2 \n" 1910 "1: \n" 1911 MEMACCESS(0) 1912 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 RGBA pixels. 1913 MEMACCESS(0) 1914 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 RGBA pixels. 1915 "vpaddl.u8 q0, q1 \n" // B 16 bytes -> 8 shorts. 1916 "vpaddl.u8 q1, q2 \n" // G 16 bytes -> 8 shorts. 1917 "vpaddl.u8 q2, q3 \n" // R 16 bytes -> 8 shorts. 1918 MEMACCESS(1) 1919 "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more RGBA pixels. 1920 MEMACCESS(1) 1921 "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 RGBA pixels. 1922 "vpadal.u8 q0, q5 \n" // B 16 bytes -> 8 shorts. 1923 "vpadal.u8 q1, q6 \n" // G 16 bytes -> 8 shorts. 1924 "vpadal.u8 q2, q7 \n" // R 16 bytes -> 8 shorts. 1925 1926 "vrshr.u16 q0, q0, #1 \n" // 2x average 1927 "vrshr.u16 q1, q1, #1 \n" 1928 "vrshr.u16 q2, q2, #1 \n" 1929 1930 "subs %4, %4, #16 \n" // 32 processed per loop. 1931 RGBTOUV(q0, q1, q2) 1932 MEMACCESS(2) 1933 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 1934 MEMACCESS(3) 1935 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 1936 "bgt 1b \n" 1937 : "+r"(src_rgba), // %0 1938 "+r"(src_stride_rgba), // %1 1939 "+r"(dst_u), // %2 1940 "+r"(dst_v), // %3 1941 "+r"(pix) // %4 1942 : 1943 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 1944 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 1945 ); 1946 } 1947 1948 void RGB24ToUVRow_NEON(const uint8* src_rgb24, int src_stride_rgb24, 1949 uint8* dst_u, uint8* dst_v, int pix) { 1950 asm volatile ( 1951 "add %1, %0, %1 \n" // src_stride + src_rgb24 1952 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 1953 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 1954 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 1955 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 1956 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 1957 "vmov.u16 q15, #0x8080 \n" // 128.5 1958 ".p2align 2 \n" 1959 "1: \n" 1960 MEMACCESS(0) 1961 "vld3.8 {d0, d2, d4}, [%0]! \n" // load 8 RGB24 pixels. 1962 MEMACCESS(0) 1963 "vld3.8 {d1, d3, d5}, [%0]! \n" // load next 8 RGB24 pixels. 1964 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts. 1965 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 1966 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts. 1967 MEMACCESS(1) 1968 "vld3.8 {d8, d10, d12}, [%1]! \n" // load 8 more RGB24 pixels. 1969 MEMACCESS(1) 1970 "vld3.8 {d9, d11, d13}, [%1]! \n" // load last 8 RGB24 pixels. 1971 "vpadal.u8 q0, q4 \n" // B 16 bytes -> 8 shorts. 1972 "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts. 1973 "vpadal.u8 q2, q6 \n" // R 16 bytes -> 8 shorts. 1974 1975 "vrshr.u16 q0, q0, #1 \n" // 2x average 1976 "vrshr.u16 q1, q1, #1 \n" 1977 "vrshr.u16 q2, q2, #1 \n" 1978 1979 "subs %4, %4, #16 \n" // 32 processed per loop. 1980 RGBTOUV(q0, q1, q2) 1981 MEMACCESS(2) 1982 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 1983 MEMACCESS(3) 1984 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 1985 "bgt 1b \n" 1986 : "+r"(src_rgb24), // %0 1987 "+r"(src_stride_rgb24), // %1 1988 "+r"(dst_u), // %2 1989 "+r"(dst_v), // %3 1990 "+r"(pix) // %4 1991 : 1992 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 1993 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 1994 ); 1995 } 1996 1997 void RAWToUVRow_NEON(const uint8* src_raw, int src_stride_raw, 1998 uint8* dst_u, uint8* dst_v, int pix) { 1999 asm volatile ( 2000 "add %1, %0, %1 \n" // src_stride + src_raw 2001 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 2002 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 2003 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 2004 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 2005 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 2006 "vmov.u16 q15, #0x8080 \n" // 128.5 2007 ".p2align 2 \n" 2008 "1: \n" 2009 MEMACCESS(0) 2010 "vld3.8 {d0, d2, d4}, [%0]! \n" // load 8 RAW pixels. 2011 MEMACCESS(0) 2012 "vld3.8 {d1, d3, d5}, [%0]! \n" // load next 8 RAW pixels. 2013 "vpaddl.u8 q2, q2 \n" // B 16 bytes -> 8 shorts. 2014 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 2015 "vpaddl.u8 q0, q0 \n" // R 16 bytes -> 8 shorts. 2016 MEMACCESS(1) 2017 "vld3.8 {d8, d10, d12}, [%1]! \n" // load 8 more RAW pixels. 2018 MEMACCESS(1) 2019 "vld3.8 {d9, d11, d13}, [%1]! \n" // load last 8 RAW pixels. 2020 "vpadal.u8 q2, q6 \n" // B 16 bytes -> 8 shorts. 2021 "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts. 2022 "vpadal.u8 q0, q4 \n" // R 16 bytes -> 8 shorts. 2023 2024 "vrshr.u16 q0, q0, #1 \n" // 2x average 2025 "vrshr.u16 q1, q1, #1 \n" 2026 "vrshr.u16 q2, q2, #1 \n" 2027 2028 "subs %4, %4, #16 \n" // 32 processed per loop. 2029 RGBTOUV(q2, q1, q0) 2030 MEMACCESS(2) 2031 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 2032 MEMACCESS(3) 2033 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 2034 "bgt 1b \n" 2035 : "+r"(src_raw), // %0 2036 "+r"(src_stride_raw), // %1 2037 "+r"(dst_u), // %2 2038 "+r"(dst_v), // %3 2039 "+r"(pix) // %4 2040 : 2041 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 2042 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 2043 ); 2044 } 2045 2046 // 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16. 2047 void RGB565ToUVRow_NEON(const uint8* src_rgb565, int src_stride_rgb565, 2048 uint8* dst_u, uint8* dst_v, int pix) { 2049 asm volatile ( 2050 "add %1, %0, %1 \n" // src_stride + src_argb 2051 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 2052 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 2053 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 2054 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 2055 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 2056 "vmov.u16 q15, #0x8080 \n" // 128.5 2057 ".p2align 2 \n" 2058 "1: \n" 2059 MEMACCESS(0) 2060 "vld1.8 {q0}, [%0]! \n" // load 8 RGB565 pixels. 2061 RGB565TOARGB 2062 "vpaddl.u8 d8, d0 \n" // B 8 bytes -> 4 shorts. 2063 "vpaddl.u8 d10, d1 \n" // G 8 bytes -> 4 shorts. 2064 "vpaddl.u8 d12, d2 \n" // R 8 bytes -> 4 shorts. 2065 MEMACCESS(0) 2066 "vld1.8 {q0}, [%0]! \n" // next 8 RGB565 pixels. 2067 RGB565TOARGB 2068 "vpaddl.u8 d9, d0 \n" // B 8 bytes -> 4 shorts. 2069 "vpaddl.u8 d11, d1 \n" // G 8 bytes -> 4 shorts. 2070 "vpaddl.u8 d13, d2 \n" // R 8 bytes -> 4 shorts. 2071 2072 MEMACCESS(1) 2073 "vld1.8 {q0}, [%1]! \n" // load 8 RGB565 pixels. 2074 RGB565TOARGB 2075 "vpadal.u8 d8, d0 \n" // B 8 bytes -> 4 shorts. 2076 "vpadal.u8 d10, d1 \n" // G 8 bytes -> 4 shorts. 2077 "vpadal.u8 d12, d2 \n" // R 8 bytes -> 4 shorts. 2078 MEMACCESS(1) 2079 "vld1.8 {q0}, [%1]! \n" // next 8 RGB565 pixels. 2080 RGB565TOARGB 2081 "vpadal.u8 d9, d0 \n" // B 8 bytes -> 4 shorts. 2082 "vpadal.u8 d11, d1 \n" // G 8 bytes -> 4 shorts. 2083 "vpadal.u8 d13, d2 \n" // R 8 bytes -> 4 shorts. 2084 2085 "vrshr.u16 q4, q4, #1 \n" // 2x average 2086 "vrshr.u16 q5, q5, #1 \n" 2087 "vrshr.u16 q6, q6, #1 \n" 2088 2089 "subs %4, %4, #16 \n" // 16 processed per loop. 2090 "vmul.s16 q8, q4, q10 \n" // B 2091 "vmls.s16 q8, q5, q11 \n" // G 2092 "vmls.s16 q8, q6, q12 \n" // R 2093 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned 2094 "vmul.s16 q9, q6, q10 \n" // R 2095 "vmls.s16 q9, q5, q14 \n" // G 2096 "vmls.s16 q9, q4, q13 \n" // B 2097 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned 2098 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U 2099 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V 2100 MEMACCESS(2) 2101 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 2102 MEMACCESS(3) 2103 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 2104 "bgt 1b \n" 2105 : "+r"(src_rgb565), // %0 2106 "+r"(src_stride_rgb565), // %1 2107 "+r"(dst_u), // %2 2108 "+r"(dst_v), // %3 2109 "+r"(pix) // %4 2110 : 2111 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 2112 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 2113 ); 2114 } 2115 2116 // 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16. 2117 void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, int src_stride_argb1555, 2118 uint8* dst_u, uint8* dst_v, int pix) { 2119 asm volatile ( 2120 "add %1, %0, %1 \n" // src_stride + src_argb 2121 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 2122 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 2123 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 2124 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 2125 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 2126 "vmov.u16 q15, #0x8080 \n" // 128.5 2127 ".p2align 2 \n" 2128 "1: \n" 2129 MEMACCESS(0) 2130 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB1555 pixels. 2131 RGB555TOARGB 2132 "vpaddl.u8 d8, d0 \n" // B 8 bytes -> 4 shorts. 2133 "vpaddl.u8 d10, d1 \n" // G 8 bytes -> 4 shorts. 2134 "vpaddl.u8 d12, d2 \n" // R 8 bytes -> 4 shorts. 2135 MEMACCESS(0) 2136 "vld1.8 {q0}, [%0]! \n" // next 8 ARGB1555 pixels. 2137 RGB555TOARGB 2138 "vpaddl.u8 d9, d0 \n" // B 8 bytes -> 4 shorts. 2139 "vpaddl.u8 d11, d1 \n" // G 8 bytes -> 4 shorts. 2140 "vpaddl.u8 d13, d2 \n" // R 8 bytes -> 4 shorts. 2141 2142 MEMACCESS(1) 2143 "vld1.8 {q0}, [%1]! \n" // load 8 ARGB1555 pixels. 2144 RGB555TOARGB 2145 "vpadal.u8 d8, d0 \n" // B 8 bytes -> 4 shorts. 2146 "vpadal.u8 d10, d1 \n" // G 8 bytes -> 4 shorts. 2147 "vpadal.u8 d12, d2 \n" // R 8 bytes -> 4 shorts. 2148 MEMACCESS(1) 2149 "vld1.8 {q0}, [%1]! \n" // next 8 ARGB1555 pixels. 2150 RGB555TOARGB 2151 "vpadal.u8 d9, d0 \n" // B 8 bytes -> 4 shorts. 2152 "vpadal.u8 d11, d1 \n" // G 8 bytes -> 4 shorts. 2153 "vpadal.u8 d13, d2 \n" // R 8 bytes -> 4 shorts. 2154 2155 "vrshr.u16 q4, q4, #1 \n" // 2x average 2156 "vrshr.u16 q5, q5, #1 \n" 2157 "vrshr.u16 q6, q6, #1 \n" 2158 2159 "subs %4, %4, #16 \n" // 16 processed per loop. 2160 "vmul.s16 q8, q4, q10 \n" // B 2161 "vmls.s16 q8, q5, q11 \n" // G 2162 "vmls.s16 q8, q6, q12 \n" // R 2163 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned 2164 "vmul.s16 q9, q6, q10 \n" // R 2165 "vmls.s16 q9, q5, q14 \n" // G 2166 "vmls.s16 q9, q4, q13 \n" // B 2167 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned 2168 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U 2169 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V 2170 MEMACCESS(2) 2171 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 2172 MEMACCESS(3) 2173 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 2174 "bgt 1b \n" 2175 : "+r"(src_argb1555), // %0 2176 "+r"(src_stride_argb1555), // %1 2177 "+r"(dst_u), // %2 2178 "+r"(dst_v), // %3 2179 "+r"(pix) // %4 2180 : 2181 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 2182 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 2183 ); 2184 } 2185 2186 // 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16. 2187 void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, int src_stride_argb4444, 2188 uint8* dst_u, uint8* dst_v, int pix) { 2189 asm volatile ( 2190 "add %1, %0, %1 \n" // src_stride + src_argb 2191 "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient 2192 "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient 2193 "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient 2194 "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient 2195 "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient 2196 "vmov.u16 q15, #0x8080 \n" // 128.5 2197 ".p2align 2 \n" 2198 "1: \n" 2199 MEMACCESS(0) 2200 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB4444 pixels. 2201 ARGB4444TOARGB 2202 "vpaddl.u8 d8, d0 \n" // B 8 bytes -> 4 shorts. 2203 "vpaddl.u8 d10, d1 \n" // G 8 bytes -> 4 shorts. 2204 "vpaddl.u8 d12, d2 \n" // R 8 bytes -> 4 shorts. 2205 MEMACCESS(0) 2206 "vld1.8 {q0}, [%0]! \n" // next 8 ARGB4444 pixels. 2207 ARGB4444TOARGB 2208 "vpaddl.u8 d9, d0 \n" // B 8 bytes -> 4 shorts. 2209 "vpaddl.u8 d11, d1 \n" // G 8 bytes -> 4 shorts. 2210 "vpaddl.u8 d13, d2 \n" // R 8 bytes -> 4 shorts. 2211 2212 MEMACCESS(1) 2213 "vld1.8 {q0}, [%1]! \n" // load 8 ARGB4444 pixels. 2214 ARGB4444TOARGB 2215 "vpadal.u8 d8, d0 \n" // B 8 bytes -> 4 shorts. 2216 "vpadal.u8 d10, d1 \n" // G 8 bytes -> 4 shorts. 2217 "vpadal.u8 d12, d2 \n" // R 8 bytes -> 4 shorts. 2218 MEMACCESS(1) 2219 "vld1.8 {q0}, [%1]! \n" // next 8 ARGB4444 pixels. 2220 ARGB4444TOARGB 2221 "vpadal.u8 d9, d0 \n" // B 8 bytes -> 4 shorts. 2222 "vpadal.u8 d11, d1 \n" // G 8 bytes -> 4 shorts. 2223 "vpadal.u8 d13, d2 \n" // R 8 bytes -> 4 shorts. 2224 2225 "vrshr.u16 q4, q4, #1 \n" // 2x average 2226 "vrshr.u16 q5, q5, #1 \n" 2227 "vrshr.u16 q6, q6, #1 \n" 2228 2229 "subs %4, %4, #16 \n" // 16 processed per loop. 2230 "vmul.s16 q8, q4, q10 \n" // B 2231 "vmls.s16 q8, q5, q11 \n" // G 2232 "vmls.s16 q8, q6, q12 \n" // R 2233 "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned 2234 "vmul.s16 q9, q6, q10 \n" // R 2235 "vmls.s16 q9, q5, q14 \n" // G 2236 "vmls.s16 q9, q4, q13 \n" // B 2237 "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned 2238 "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U 2239 "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V 2240 MEMACCESS(2) 2241 "vst1.8 {d0}, [%2]! \n" // store 8 pixels U. 2242 MEMACCESS(3) 2243 "vst1.8 {d1}, [%3]! \n" // store 8 pixels V. 2244 "bgt 1b \n" 2245 : "+r"(src_argb4444), // %0 2246 "+r"(src_stride_argb4444), // %1 2247 "+r"(dst_u), // %2 2248 "+r"(dst_v), // %3 2249 "+r"(pix) // %4 2250 : 2251 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", 2252 "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" 2253 ); 2254 } 2255 2256 void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int pix) { 2257 asm volatile ( 2258 "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient 2259 "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient 2260 "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient 2261 "vmov.u8 d27, #16 \n" // Add 16 constant 2262 ".p2align 2 \n" 2263 "1: \n" 2264 MEMACCESS(0) 2265 "vld1.8 {q0}, [%0]! \n" // load 8 RGB565 pixels. 2266 "subs %2, %2, #8 \n" // 8 processed per loop. 2267 RGB565TOARGB 2268 "vmull.u8 q2, d0, d24 \n" // B 2269 "vmlal.u8 q2, d1, d25 \n" // G 2270 "vmlal.u8 q2, d2, d26 \n" // R 2271 "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y 2272 "vqadd.u8 d0, d27 \n" 2273 MEMACCESS(1) 2274 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 2275 "bgt 1b \n" 2276 : "+r"(src_rgb565), // %0 2277 "+r"(dst_y), // %1 2278 "+r"(pix) // %2 2279 : 2280 : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13" 2281 ); 2282 } 2283 2284 void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int pix) { 2285 asm volatile ( 2286 "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient 2287 "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient 2288 "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient 2289 "vmov.u8 d27, #16 \n" // Add 16 constant 2290 ".p2align 2 \n" 2291 "1: \n" 2292 MEMACCESS(0) 2293 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB1555 pixels. 2294 "subs %2, %2, #8 \n" // 8 processed per loop. 2295 ARGB1555TOARGB 2296 "vmull.u8 q2, d0, d24 \n" // B 2297 "vmlal.u8 q2, d1, d25 \n" // G 2298 "vmlal.u8 q2, d2, d26 \n" // R 2299 "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y 2300 "vqadd.u8 d0, d27 \n" 2301 MEMACCESS(1) 2302 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 2303 "bgt 1b \n" 2304 : "+r"(src_argb1555), // %0 2305 "+r"(dst_y), // %1 2306 "+r"(pix) // %2 2307 : 2308 : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13" 2309 ); 2310 } 2311 2312 void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int pix) { 2313 asm volatile ( 2314 "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient 2315 "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient 2316 "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient 2317 "vmov.u8 d27, #16 \n" // Add 16 constant 2318 ".p2align 2 \n" 2319 "1: \n" 2320 MEMACCESS(0) 2321 "vld1.8 {q0}, [%0]! \n" // load 8 ARGB4444 pixels. 2322 "subs %2, %2, #8 \n" // 8 processed per loop. 2323 ARGB4444TOARGB 2324 "vmull.u8 q2, d0, d24 \n" // B 2325 "vmlal.u8 q2, d1, d25 \n" // G 2326 "vmlal.u8 q2, d2, d26 \n" // R 2327 "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y 2328 "vqadd.u8 d0, d27 \n" 2329 MEMACCESS(1) 2330 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 2331 "bgt 1b \n" 2332 : "+r"(src_argb4444), // %0 2333 "+r"(dst_y), // %1 2334 "+r"(pix) // %2 2335 : 2336 : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13" 2337 ); 2338 } 2339 2340 void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int pix) { 2341 asm volatile ( 2342 "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient 2343 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient 2344 "vmov.u8 d6, #13 \n" // B * 0.1016 coefficient 2345 "vmov.u8 d7, #16 \n" // Add 16 constant 2346 ".p2align 2 \n" 2347 "1: \n" 2348 MEMACCESS(0) 2349 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of BGRA. 2350 "subs %2, %2, #8 \n" // 8 processed per loop. 2351 "vmull.u8 q8, d1, d4 \n" // R 2352 "vmlal.u8 q8, d2, d5 \n" // G 2353 "vmlal.u8 q8, d3, d6 \n" // B 2354 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y 2355 "vqadd.u8 d0, d7 \n" 2356 MEMACCESS(1) 2357 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 2358 "bgt 1b \n" 2359 : "+r"(src_bgra), // %0 2360 "+r"(dst_y), // %1 2361 "+r"(pix) // %2 2362 : 2363 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8" 2364 ); 2365 } 2366 2367 void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int pix) { 2368 asm volatile ( 2369 "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient 2370 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient 2371 "vmov.u8 d6, #13 \n" // B * 0.1016 coefficient 2372 "vmov.u8 d7, #16 \n" // Add 16 constant 2373 ".p2align 2 \n" 2374 "1: \n" 2375 MEMACCESS(0) 2376 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ABGR. 2377 "subs %2, %2, #8 \n" // 8 processed per loop. 2378 "vmull.u8 q8, d0, d4 \n" // R 2379 "vmlal.u8 q8, d1, d5 \n" // G 2380 "vmlal.u8 q8, d2, d6 \n" // B 2381 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y 2382 "vqadd.u8 d0, d7 \n" 2383 MEMACCESS(1) 2384 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 2385 "bgt 1b \n" 2386 : "+r"(src_abgr), // %0 2387 "+r"(dst_y), // %1 2388 "+r"(pix) // %2 2389 : 2390 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8" 2391 ); 2392 } 2393 2394 void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int pix) { 2395 asm volatile ( 2396 "vmov.u8 d4, #13 \n" // B * 0.1016 coefficient 2397 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient 2398 "vmov.u8 d6, #33 \n" // R * 0.2578 coefficient 2399 "vmov.u8 d7, #16 \n" // Add 16 constant 2400 ".p2align 2 \n" 2401 "1: \n" 2402 MEMACCESS(0) 2403 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of RGBA. 2404 "subs %2, %2, #8 \n" // 8 processed per loop. 2405 "vmull.u8 q8, d1, d4 \n" // B 2406 "vmlal.u8 q8, d2, d5 \n" // G 2407 "vmlal.u8 q8, d3, d6 \n" // R 2408 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y 2409 "vqadd.u8 d0, d7 \n" 2410 MEMACCESS(1) 2411 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 2412 "bgt 1b \n" 2413 : "+r"(src_rgba), // %0 2414 "+r"(dst_y), // %1 2415 "+r"(pix) // %2 2416 : 2417 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8" 2418 ); 2419 } 2420 2421 void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int pix) { 2422 asm volatile ( 2423 "vmov.u8 d4, #13 \n" // B * 0.1016 coefficient 2424 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient 2425 "vmov.u8 d6, #33 \n" // R * 0.2578 coefficient 2426 "vmov.u8 d7, #16 \n" // Add 16 constant 2427 ".p2align 2 \n" 2428 "1: \n" 2429 MEMACCESS(0) 2430 "vld3.8 {d0, d1, d2}, [%0]! \n" // load 8 pixels of RGB24. 2431 "subs %2, %2, #8 \n" // 8 processed per loop. 2432 "vmull.u8 q8, d0, d4 \n" // B 2433 "vmlal.u8 q8, d1, d5 \n" // G 2434 "vmlal.u8 q8, d2, d6 \n" // R 2435 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y 2436 "vqadd.u8 d0, d7 \n" 2437 MEMACCESS(1) 2438 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 2439 "bgt 1b \n" 2440 : "+r"(src_rgb24), // %0 2441 "+r"(dst_y), // %1 2442 "+r"(pix) // %2 2443 : 2444 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8" 2445 ); 2446 } 2447 2448 void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int pix) { 2449 asm volatile ( 2450 "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient 2451 "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient 2452 "vmov.u8 d6, #13 \n" // B * 0.1016 coefficient 2453 "vmov.u8 d7, #16 \n" // Add 16 constant 2454 ".p2align 2 \n" 2455 "1: \n" 2456 MEMACCESS(0) 2457 "vld3.8 {d0, d1, d2}, [%0]! \n" // load 8 pixels of RAW. 2458 "subs %2, %2, #8 \n" // 8 processed per loop. 2459 "vmull.u8 q8, d0, d4 \n" // B 2460 "vmlal.u8 q8, d1, d5 \n" // G 2461 "vmlal.u8 q8, d2, d6 \n" // R 2462 "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y 2463 "vqadd.u8 d0, d7 \n" 2464 MEMACCESS(1) 2465 "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y. 2466 "bgt 1b \n" 2467 : "+r"(src_raw), // %0 2468 "+r"(dst_y), // %1 2469 "+r"(pix) // %2 2470 : 2471 : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8" 2472 ); 2473 } 2474 2475 // Bilinear filter 16x2 -> 16x1 2476 void InterpolateRow_NEON(uint8* dst_ptr, 2477 const uint8* src_ptr, ptrdiff_t src_stride, 2478 int dst_width, int source_y_fraction) { 2479 asm volatile ( 2480 "cmp %4, #0 \n" 2481 "beq 100f \n" 2482 "add %2, %1 \n" 2483 "cmp %4, #64 \n" 2484 "beq 75f \n" 2485 "cmp %4, #128 \n" 2486 "beq 50f \n" 2487 "cmp %4, #192 \n" 2488 "beq 25f \n" 2489 2490 "vdup.8 d5, %4 \n" 2491 "rsb %4, #256 \n" 2492 "vdup.8 d4, %4 \n" 2493 // General purpose row blend. 2494 "1: \n" 2495 MEMACCESS(1) 2496 "vld1.8 {q0}, [%1]! \n" 2497 MEMACCESS(2) 2498 "vld1.8 {q1}, [%2]! \n" 2499 "subs %3, %3, #16 \n" 2500 "vmull.u8 q13, d0, d4 \n" 2501 "vmull.u8 q14, d1, d4 \n" 2502 "vmlal.u8 q13, d2, d5 \n" 2503 "vmlal.u8 q14, d3, d5 \n" 2504 "vrshrn.u16 d0, q13, #8 \n" 2505 "vrshrn.u16 d1, q14, #8 \n" 2506 MEMACCESS(0) 2507 "vst1.8 {q0}, [%0]! \n" 2508 "bgt 1b \n" 2509 "b 99f \n" 2510 2511 // Blend 25 / 75. 2512 "25: \n" 2513 MEMACCESS(1) 2514 "vld1.8 {q0}, [%1]! \n" 2515 MEMACCESS(2) 2516 "vld1.8 {q1}, [%2]! \n" 2517 "subs %3, %3, #16 \n" 2518 "vrhadd.u8 q0, q1 \n" 2519 "vrhadd.u8 q0, q1 \n" 2520 MEMACCESS(0) 2521 "vst1.8 {q0}, [%0]! \n" 2522 "bgt 25b \n" 2523 "b 99f \n" 2524 2525 // Blend 50 / 50. 2526 "50: \n" 2527 MEMACCESS(1) 2528 "vld1.8 {q0}, [%1]! \n" 2529 MEMACCESS(2) 2530 "vld1.8 {q1}, [%2]! \n" 2531 "subs %3, %3, #16 \n" 2532 "vrhadd.u8 q0, q1 \n" 2533 MEMACCESS(0) 2534 "vst1.8 {q0}, [%0]! \n" 2535 "bgt 50b \n" 2536 "b 99f \n" 2537 2538 // Blend 75 / 25. 2539 "75: \n" 2540 MEMACCESS(1) 2541 "vld1.8 {q1}, [%1]! \n" 2542 MEMACCESS(2) 2543 "vld1.8 {q0}, [%2]! \n" 2544 "subs %3, %3, #16 \n" 2545 "vrhadd.u8 q0, q1 \n" 2546 "vrhadd.u8 q0, q1 \n" 2547 MEMACCESS(0) 2548 "vst1.8 {q0}, [%0]! \n" 2549 "bgt 75b \n" 2550 "b 99f \n" 2551 2552 // Blend 100 / 0 - Copy row unchanged. 2553 "100: \n" 2554 MEMACCESS(1) 2555 "vld1.8 {q0}, [%1]! \n" 2556 "subs %3, %3, #16 \n" 2557 MEMACCESS(0) 2558 "vst1.8 {q0}, [%0]! \n" 2559 "bgt 100b \n" 2560 2561 "99: \n" 2562 : "+r"(dst_ptr), // %0 2563 "+r"(src_ptr), // %1 2564 "+r"(src_stride), // %2 2565 "+r"(dst_width), // %3 2566 "+r"(source_y_fraction) // %4 2567 : 2568 : "cc", "memory", "q0", "q1", "d4", "d5", "q13", "q14" 2569 ); 2570 } 2571 2572 // dr * (256 - sa) / 256 + sr = dr - dr * sa / 256 + sr 2573 void ARGBBlendRow_NEON(const uint8* src_argb0, const uint8* src_argb1, 2574 uint8* dst_argb, int width) { 2575 asm volatile ( 2576 "subs %3, #8 \n" 2577 "blt 89f \n" 2578 // Blend 8 pixels. 2579 "8: \n" 2580 MEMACCESS(0) 2581 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ARGB0. 2582 MEMACCESS(1) 2583 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load 8 pixels of ARGB1. 2584 "subs %3, %3, #8 \n" // 8 processed per loop. 2585 "vmull.u8 q10, d4, d3 \n" // db * a 2586 "vmull.u8 q11, d5, d3 \n" // dg * a 2587 "vmull.u8 q12, d6, d3 \n" // dr * a 2588 "vqrshrn.u16 d20, q10, #8 \n" // db >>= 8 2589 "vqrshrn.u16 d21, q11, #8 \n" // dg >>= 8 2590 "vqrshrn.u16 d22, q12, #8 \n" // dr >>= 8 2591 "vqsub.u8 q2, q2, q10 \n" // dbg - dbg * a / 256 2592 "vqsub.u8 d6, d6, d22 \n" // dr - dr * a / 256 2593 "vqadd.u8 q0, q0, q2 \n" // + sbg 2594 "vqadd.u8 d2, d2, d6 \n" // + sr 2595 "vmov.u8 d3, #255 \n" // a = 255 2596 MEMACCESS(2) 2597 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 pixels of ARGB. 2598 "bge 8b \n" 2599 2600 "89: \n" 2601 "adds %3, #8-1 \n" 2602 "blt 99f \n" 2603 2604 // Blend 1 pixels. 2605 "1: \n" 2606 MEMACCESS(0) 2607 "vld4.8 {d0[0],d1[0],d2[0],d3[0]}, [%0]! \n" // load 1 pixel ARGB0. 2608 MEMACCESS(1) 2609 "vld4.8 {d4[0],d5[0],d6[0],d7[0]}, [%1]! \n" // load 1 pixel ARGB1. 2610 "subs %3, %3, #1 \n" // 1 processed per loop. 2611 "vmull.u8 q10, d4, d3 \n" // db * a 2612 "vmull.u8 q11, d5, d3 \n" // dg * a 2613 "vmull.u8 q12, d6, d3 \n" // dr * a 2614 "vqrshrn.u16 d20, q10, #8 \n" // db >>= 8 2615 "vqrshrn.u16 d21, q11, #8 \n" // dg >>= 8 2616 "vqrshrn.u16 d22, q12, #8 \n" // dr >>= 8 2617 "vqsub.u8 q2, q2, q10 \n" // dbg - dbg * a / 256 2618 "vqsub.u8 d6, d6, d22 \n" // dr - dr * a / 256 2619 "vqadd.u8 q0, q0, q2 \n" // + sbg 2620 "vqadd.u8 d2, d2, d6 \n" // + sr 2621 "vmov.u8 d3, #255 \n" // a = 255 2622 MEMACCESS(2) 2623 "vst4.8 {d0[0],d1[0],d2[0],d3[0]}, [%2]! \n" // store 1 pixel. 2624 "bge 1b \n" 2625 2626 "99: \n" 2627 2628 : "+r"(src_argb0), // %0 2629 "+r"(src_argb1), // %1 2630 "+r"(dst_argb), // %2 2631 "+r"(width) // %3 2632 : 2633 : "cc", "memory", "q0", "q1", "q2", "q3", "q10", "q11", "q12" 2634 ); 2635 } 2636 2637 // Attenuate 8 pixels at a time. 2638 void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { 2639 asm volatile ( 2640 // Attenuate 8 pixels. 2641 "1: \n" 2642 MEMACCESS(0) 2643 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ARGB. 2644 "subs %2, %2, #8 \n" // 8 processed per loop. 2645 "vmull.u8 q10, d0, d3 \n" // b * a 2646 "vmull.u8 q11, d1, d3 \n" // g * a 2647 "vmull.u8 q12, d2, d3 \n" // r * a 2648 "vqrshrn.u16 d0, q10, #8 \n" // b >>= 8 2649 "vqrshrn.u16 d1, q11, #8 \n" // g >>= 8 2650 "vqrshrn.u16 d2, q12, #8 \n" // r >>= 8 2651 MEMACCESS(1) 2652 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB. 2653 "bgt 1b \n" 2654 : "+r"(src_argb), // %0 2655 "+r"(dst_argb), // %1 2656 "+r"(width) // %2 2657 : 2658 : "cc", "memory", "q0", "q1", "q10", "q11", "q12" 2659 ); 2660 } 2661 2662 // Quantize 8 ARGB pixels (32 bytes). 2663 // dst = (dst * scale >> 16) * interval_size + interval_offset; 2664 void ARGBQuantizeRow_NEON(uint8* dst_argb, int scale, int interval_size, 2665 int interval_offset, int width) { 2666 asm volatile ( 2667 "vdup.u16 q8, %2 \n" 2668 "vshr.u16 q8, q8, #1 \n" // scale >>= 1 2669 "vdup.u16 q9, %3 \n" // interval multiply. 2670 "vdup.u16 q10, %4 \n" // interval add 2671 2672 // 8 pixel loop. 2673 ".p2align 2 \n" 2674 "1: \n" 2675 MEMACCESS(0) 2676 "vld4.8 {d0, d2, d4, d6}, [%0] \n" // load 8 pixels of ARGB. 2677 "subs %1, %1, #8 \n" // 8 processed per loop. 2678 "vmovl.u8 q0, d0 \n" // b (0 .. 255) 2679 "vmovl.u8 q1, d2 \n" 2680 "vmovl.u8 q2, d4 \n" 2681 "vqdmulh.s16 q0, q0, q8 \n" // b * scale 2682 "vqdmulh.s16 q1, q1, q8 \n" // g 2683 "vqdmulh.s16 q2, q2, q8 \n" // r 2684 "vmul.u16 q0, q0, q9 \n" // b * interval_size 2685 "vmul.u16 q1, q1, q9 \n" // g 2686 "vmul.u16 q2, q2, q9 \n" // r 2687 "vadd.u16 q0, q0, q10 \n" // b + interval_offset 2688 "vadd.u16 q1, q1, q10 \n" // g 2689 "vadd.u16 q2, q2, q10 \n" // r 2690 "vqmovn.u16 d0, q0 \n" 2691 "vqmovn.u16 d2, q1 \n" 2692 "vqmovn.u16 d4, q2 \n" 2693 MEMACCESS(0) 2694 "vst4.8 {d0, d2, d4, d6}, [%0]! \n" // store 8 pixels of ARGB. 2695 "bgt 1b \n" 2696 : "+r"(dst_argb), // %0 2697 "+r"(width) // %1 2698 : "r"(scale), // %2 2699 "r"(interval_size), // %3 2700 "r"(interval_offset) // %4 2701 : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10" 2702 ); 2703 } 2704 2705 // Shade 8 pixels at a time by specified value. 2706 // NOTE vqrdmulh.s16 q10, q10, d0[0] must use a scaler register from 0 to 8. 2707 // Rounding in vqrdmulh does +1 to high if high bit of low s16 is set. 2708 void ARGBShadeRow_NEON(const uint8* src_argb, uint8* dst_argb, int width, 2709 uint32 value) { 2710 asm volatile ( 2711 "vdup.u32 q0, %3 \n" // duplicate scale value. 2712 "vzip.u8 d0, d1 \n" // d0 aarrggbb. 2713 "vshr.u16 q0, q0, #1 \n" // scale / 2. 2714 2715 // 8 pixel loop. 2716 ".p2align 2 \n" 2717 "1: \n" 2718 MEMACCESS(0) 2719 "vld4.8 {d20, d22, d24, d26}, [%0]! \n" // load 8 pixels of ARGB. 2720 "subs %2, %2, #8 \n" // 8 processed per loop. 2721 "vmovl.u8 q10, d20 \n" // b (0 .. 255) 2722 "vmovl.u8 q11, d22 \n" 2723 "vmovl.u8 q12, d24 \n" 2724 "vmovl.u8 q13, d26 \n" 2725 "vqrdmulh.s16 q10, q10, d0[0] \n" // b * scale * 2 2726 "vqrdmulh.s16 q11, q11, d0[1] \n" // g 2727 "vqrdmulh.s16 q12, q12, d0[2] \n" // r 2728 "vqrdmulh.s16 q13, q13, d0[3] \n" // a 2729 "vqmovn.u16 d20, q10 \n" 2730 "vqmovn.u16 d22, q11 \n" 2731 "vqmovn.u16 d24, q12 \n" 2732 "vqmovn.u16 d26, q13 \n" 2733 MEMACCESS(1) 2734 "vst4.8 {d20, d22, d24, d26}, [%1]! \n" // store 8 pixels of ARGB. 2735 "bgt 1b \n" 2736 : "+r"(src_argb), // %0 2737 "+r"(dst_argb), // %1 2738 "+r"(width) // %2 2739 : "r"(value) // %3 2740 : "cc", "memory", "q0", "q10", "q11", "q12", "q13" 2741 ); 2742 } 2743 2744 // Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels 2745 // Similar to ARGBToYJ but stores ARGB. 2746 // C code is (15 * b + 75 * g + 38 * r + 64) >> 7; 2747 void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { 2748 asm volatile ( 2749 "vmov.u8 d24, #15 \n" // B * 0.11400 coefficient 2750 "vmov.u8 d25, #75 \n" // G * 0.58700 coefficient 2751 "vmov.u8 d26, #38 \n" // R * 0.29900 coefficient 2752 ".p2align 2 \n" 2753 "1: \n" 2754 MEMACCESS(0) 2755 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels. 2756 "subs %2, %2, #8 \n" // 8 processed per loop. 2757 "vmull.u8 q2, d0, d24 \n" // B 2758 "vmlal.u8 q2, d1, d25 \n" // G 2759 "vmlal.u8 q2, d2, d26 \n" // R 2760 "vqrshrun.s16 d0, q2, #7 \n" // 15 bit to 8 bit B 2761 "vmov d1, d0 \n" // G 2762 "vmov d2, d0 \n" // R 2763 MEMACCESS(1) 2764 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 ARGB pixels. 2765 "bgt 1b \n" 2766 : "+r"(src_argb), // %0 2767 "+r"(dst_argb), // %1 2768 "+r"(width) // %2 2769 : 2770 : "cc", "memory", "q0", "q1", "q2", "q12", "q13" 2771 ); 2772 } 2773 2774 // Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels. 2775 // b = (r * 35 + g * 68 + b * 17) >> 7 2776 // g = (r * 45 + g * 88 + b * 22) >> 7 2777 // r = (r * 50 + g * 98 + b * 24) >> 7 2778 void ARGBSepiaRow_NEON(uint8* dst_argb, int width) { 2779 asm volatile ( 2780 "vmov.u8 d20, #17 \n" // BB coefficient 2781 "vmov.u8 d21, #68 \n" // BG coefficient 2782 "vmov.u8 d22, #35 \n" // BR coefficient 2783 "vmov.u8 d24, #22 \n" // GB coefficient 2784 "vmov.u8 d25, #88 \n" // GG coefficient 2785 "vmov.u8 d26, #45 \n" // GR coefficient 2786 "vmov.u8 d28, #24 \n" // BB coefficient 2787 "vmov.u8 d29, #98 \n" // BG coefficient 2788 "vmov.u8 d30, #50 \n" // BR coefficient 2789 ".p2align 2 \n" 2790 "1: \n" 2791 MEMACCESS(0) 2792 "vld4.8 {d0, d1, d2, d3}, [%0] \n" // load 8 ARGB pixels. 2793 "subs %1, %1, #8 \n" // 8 processed per loop. 2794 "vmull.u8 q2, d0, d20 \n" // B to Sepia B 2795 "vmlal.u8 q2, d1, d21 \n" // G 2796 "vmlal.u8 q2, d2, d22 \n" // R 2797 "vmull.u8 q3, d0, d24 \n" // B to Sepia G 2798 "vmlal.u8 q3, d1, d25 \n" // G 2799 "vmlal.u8 q3, d2, d26 \n" // R 2800 "vmull.u8 q8, d0, d28 \n" // B to Sepia R 2801 "vmlal.u8 q8, d1, d29 \n" // G 2802 "vmlal.u8 q8, d2, d30 \n" // R 2803 "vqshrn.u16 d0, q2, #7 \n" // 16 bit to 8 bit B 2804 "vqshrn.u16 d1, q3, #7 \n" // 16 bit to 8 bit G 2805 "vqshrn.u16 d2, q8, #7 \n" // 16 bit to 8 bit R 2806 MEMACCESS(0) 2807 "vst4.8 {d0, d1, d2, d3}, [%0]! \n" // store 8 ARGB pixels. 2808 "bgt 1b \n" 2809 : "+r"(dst_argb), // %0 2810 "+r"(width) // %1 2811 : 2812 : "cc", "memory", "q0", "q1", "q2", "q3", 2813 "q10", "q11", "q12", "q13", "q14", "q15" 2814 ); 2815 } 2816 2817 // Tranform 8 ARGB pixels (32 bytes) with color matrix. 2818 // TODO(fbarchard): Was same as Sepia except matrix is provided. This function 2819 // needs to saturate. Consider doing a non-saturating version. 2820 void ARGBColorMatrixRow_NEON(const uint8* src_argb, uint8* dst_argb, 2821 const int8* matrix_argb, int width) { 2822 asm volatile ( 2823 MEMACCESS(3) 2824 "vld1.8 {q2}, [%3] \n" // load 3 ARGB vectors. 2825 "vmovl.s8 q0, d4 \n" // B,G coefficients s16. 2826 "vmovl.s8 q1, d5 \n" // R,A coefficients s16. 2827 2828 ".p2align 2 \n" 2829 "1: \n" 2830 MEMACCESS(0) 2831 "vld4.8 {d16, d18, d20, d22}, [%0]! \n" // load 8 ARGB pixels. 2832 "subs %2, %2, #8 \n" // 8 processed per loop. 2833 "vmovl.u8 q8, d16 \n" // b (0 .. 255) 16 bit 2834 "vmovl.u8 q9, d18 \n" // g 2835 "vmovl.u8 q10, d20 \n" // r 2836 "vmovl.u8 q15, d22 \n" // a 2837 "vmul.s16 q12, q8, d0[0] \n" // B = B * Matrix B 2838 "vmul.s16 q13, q8, d1[0] \n" // G = B * Matrix G 2839 "vmul.s16 q14, q8, d2[0] \n" // R = B * Matrix R 2840 "vmul.s16 q15, q8, d3[0] \n" // A = B * Matrix A 2841 "vmul.s16 q4, q9, d0[1] \n" // B += G * Matrix B 2842 "vmul.s16 q5, q9, d1[1] \n" // G += G * Matrix G 2843 "vmul.s16 q6, q9, d2[1] \n" // R += G * Matrix R 2844 "vmul.s16 q7, q9, d3[1] \n" // A += G * Matrix A 2845 "vqadd.s16 q12, q12, q4 \n" // Accumulate B 2846 "vqadd.s16 q13, q13, q5 \n" // Accumulate G 2847 "vqadd.s16 q14, q14, q6 \n" // Accumulate R 2848 "vqadd.s16 q15, q15, q7 \n" // Accumulate A 2849 "vmul.s16 q4, q10, d0[2] \n" // B += R * Matrix B 2850 "vmul.s16 q5, q10, d1[2] \n" // G += R * Matrix G 2851 "vmul.s16 q6, q10, d2[2] \n" // R += R * Matrix R 2852 "vmul.s16 q7, q10, d3[2] \n" // A += R * Matrix A 2853 "vqadd.s16 q12, q12, q4 \n" // Accumulate B 2854 "vqadd.s16 q13, q13, q5 \n" // Accumulate G 2855 "vqadd.s16 q14, q14, q6 \n" // Accumulate R 2856 "vqadd.s16 q15, q15, q7 \n" // Accumulate A 2857 "vmul.s16 q4, q15, d0[3] \n" // B += A * Matrix B 2858 "vmul.s16 q5, q15, d1[3] \n" // G += A * Matrix G 2859 "vmul.s16 q6, q15, d2[3] \n" // R += A * Matrix R 2860 "vmul.s16 q7, q15, d3[3] \n" // A += A * Matrix A 2861 "vqadd.s16 q12, q12, q4 \n" // Accumulate B 2862 "vqadd.s16 q13, q13, q5 \n" // Accumulate G 2863 "vqadd.s16 q14, q14, q6 \n" // Accumulate R 2864 "vqadd.s16 q15, q15, q7 \n" // Accumulate A 2865 "vqshrun.s16 d16, q12, #6 \n" // 16 bit to 8 bit B 2866 "vqshrun.s16 d18, q13, #6 \n" // 16 bit to 8 bit G 2867 "vqshrun.s16 d20, q14, #6 \n" // 16 bit to 8 bit R 2868 "vqshrun.s16 d22, q15, #6 \n" // 16 bit to 8 bit A 2869 MEMACCESS(1) 2870 "vst4.8 {d16, d18, d20, d22}, [%1]! \n" // store 8 ARGB pixels. 2871 "bgt 1b \n" 2872 : "+r"(src_argb), // %0 2873 "+r"(dst_argb), // %1 2874 "+r"(width) // %2 2875 : "r"(matrix_argb) // %3 2876 : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", 2877 "q10", "q11", "q12", "q13", "q14", "q15" 2878 ); 2879 } 2880 2881 // TODO(fbarchard): fix vqshrun in ARGBMultiplyRow_NEON and reenable. 2882 #ifdef HAS_ARGBMULTIPLYROW_NEON 2883 // Multiply 2 rows of ARGB pixels together, 8 pixels at a time. 2884 void ARGBMultiplyRow_NEON(const uint8* src_argb0, const uint8* src_argb1, 2885 uint8* dst_argb, int width) { 2886 asm volatile ( 2887 // 8 pixel loop. 2888 ".p2align 2 \n" 2889 "1: \n" 2890 MEMACCESS(0) 2891 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. 2892 MEMACCESS(1) 2893 "vld4.8 {d1, d3, d5, d7}, [%1]! \n" // load 8 more ARGB pixels. 2894 "subs %3, %3, #8 \n" // 8 processed per loop. 2895 "vmull.u8 q0, d0, d1 \n" // multiply B 2896 "vmull.u8 q1, d2, d3 \n" // multiply G 2897 "vmull.u8 q2, d4, d5 \n" // multiply R 2898 "vmull.u8 q3, d6, d7 \n" // multiply A 2899 "vrshrn.u16 d0, q0, #8 \n" // 16 bit to 8 bit B 2900 "vrshrn.u16 d1, q1, #8 \n" // 16 bit to 8 bit G 2901 "vrshrn.u16 d2, q2, #8 \n" // 16 bit to 8 bit R 2902 "vrshrn.u16 d3, q3, #8 \n" // 16 bit to 8 bit A 2903 MEMACCESS(2) 2904 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels. 2905 "bgt 1b \n" 2906 2907 : "+r"(src_argb0), // %0 2908 "+r"(src_argb1), // %1 2909 "+r"(dst_argb), // %2 2910 "+r"(width) // %3 2911 : 2912 : "cc", "memory", "q0", "q1", "q2", "q3" 2913 ); 2914 } 2915 #endif // HAS_ARGBMULTIPLYROW_NEON 2916 2917 // Add 2 rows of ARGB pixels together, 8 pixels at a time. 2918 void ARGBAddRow_NEON(const uint8* src_argb0, const uint8* src_argb1, 2919 uint8* dst_argb, int width) { 2920 asm volatile ( 2921 // 8 pixel loop. 2922 ".p2align 2 \n" 2923 "1: \n" 2924 MEMACCESS(0) 2925 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels. 2926 MEMACCESS(1) 2927 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load 8 more ARGB pixels. 2928 "subs %3, %3, #8 \n" // 8 processed per loop. 2929 "vqadd.u8 q0, q0, q2 \n" // add B, G 2930 "vqadd.u8 q1, q1, q3 \n" // add R, A 2931 MEMACCESS(2) 2932 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels. 2933 "bgt 1b \n" 2934 2935 : "+r"(src_argb0), // %0 2936 "+r"(src_argb1), // %1 2937 "+r"(dst_argb), // %2 2938 "+r"(width) // %3 2939 : 2940 : "cc", "memory", "q0", "q1", "q2", "q3" 2941 ); 2942 } 2943 2944 // Subtract 2 rows of ARGB pixels, 8 pixels at a time. 2945 void ARGBSubtractRow_NEON(const uint8* src_argb0, const uint8* src_argb1, 2946 uint8* dst_argb, int width) { 2947 asm volatile ( 2948 // 8 pixel loop. 2949 ".p2align 2 \n" 2950 "1: \n" 2951 MEMACCESS(0) 2952 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels. 2953 MEMACCESS(1) 2954 "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load 8 more ARGB pixels. 2955 "subs %3, %3, #8 \n" // 8 processed per loop. 2956 "vqsub.u8 q0, q0, q2 \n" // subtract B, G 2957 "vqsub.u8 q1, q1, q3 \n" // subtract R, A 2958 MEMACCESS(2) 2959 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels. 2960 "bgt 1b \n" 2961 2962 : "+r"(src_argb0), // %0 2963 "+r"(src_argb1), // %1 2964 "+r"(dst_argb), // %2 2965 "+r"(width) // %3 2966 : 2967 : "cc", "memory", "q0", "q1", "q2", "q3" 2968 ); 2969 } 2970 2971 // Adds Sobel X and Sobel Y and stores Sobel into ARGB. 2972 // A = 255 2973 // R = Sobel 2974 // G = Sobel 2975 // B = Sobel 2976 void SobelRow_NEON(const uint8* src_sobelx, const uint8* src_sobely, 2977 uint8* dst_argb, int width) { 2978 asm volatile ( 2979 "vmov.u8 d3, #255 \n" // alpha 2980 // 8 pixel loop. 2981 ".p2align 2 \n" 2982 "1: \n" 2983 MEMACCESS(0) 2984 "vld1.8 {d0}, [%0]! \n" // load 8 sobelx. 2985 MEMACCESS(1) 2986 "vld1.8 {d1}, [%1]! \n" // load 8 sobely. 2987 "subs %3, %3, #8 \n" // 8 processed per loop. 2988 "vqadd.u8 d0, d0, d1 \n" // add 2989 "vmov.u8 d1, d0 \n" 2990 "vmov.u8 d2, d0 \n" 2991 MEMACCESS(2) 2992 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels. 2993 "bgt 1b \n" 2994 : "+r"(src_sobelx), // %0 2995 "+r"(src_sobely), // %1 2996 "+r"(dst_argb), // %2 2997 "+r"(width) // %3 2998 : 2999 : "cc", "memory", "q0", "q1" 3000 ); 3001 } 3002 3003 // Adds Sobel X and Sobel Y and stores Sobel into plane. 3004 void SobelToPlaneRow_NEON(const uint8* src_sobelx, const uint8* src_sobely, 3005 uint8* dst_y, int width) { 3006 asm volatile ( 3007 // 16 pixel loop. 3008 ".p2align 2 \n" 3009 "1: \n" 3010 MEMACCESS(0) 3011 "vld1.8 {q0}, [%0]! \n" // load 16 sobelx. 3012 MEMACCESS(1) 3013 "vld1.8 {q1}, [%1]! \n" // load 16 sobely. 3014 "subs %3, %3, #16 \n" // 16 processed per loop. 3015 "vqadd.u8 q0, q0, q1 \n" // add 3016 MEMACCESS(2) 3017 "vst1.8 {q0}, [%2]! \n" // store 16 pixels. 3018 "bgt 1b \n" 3019 : "+r"(src_sobelx), // %0 3020 "+r"(src_sobely), // %1 3021 "+r"(dst_y), // %2 3022 "+r"(width) // %3 3023 : 3024 : "cc", "memory", "q0", "q1" 3025 ); 3026 } 3027 3028 // Mixes Sobel X, Sobel Y and Sobel into ARGB. 3029 // A = 255 3030 // R = Sobel X 3031 // G = Sobel 3032 // B = Sobel Y 3033 void SobelXYRow_NEON(const uint8* src_sobelx, const uint8* src_sobely, 3034 uint8* dst_argb, int width) { 3035 asm volatile ( 3036 "vmov.u8 d3, #255 \n" // alpha 3037 // 8 pixel loop. 3038 ".p2align 2 \n" 3039 "1: \n" 3040 MEMACCESS(0) 3041 "vld1.8 {d2}, [%0]! \n" // load 8 sobelx. 3042 MEMACCESS(1) 3043 "vld1.8 {d0}, [%1]! \n" // load 8 sobely. 3044 "subs %3, %3, #8 \n" // 8 processed per loop. 3045 "vqadd.u8 d1, d0, d2 \n" // add 3046 MEMACCESS(2) 3047 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels. 3048 "bgt 1b \n" 3049 : "+r"(src_sobelx), // %0 3050 "+r"(src_sobely), // %1 3051 "+r"(dst_argb), // %2 3052 "+r"(width) // %3 3053 : 3054 : "cc", "memory", "q0", "q1" 3055 ); 3056 } 3057 3058 // SobelX as a matrix is 3059 // -1 0 1 3060 // -2 0 2 3061 // -1 0 1 3062 void SobelXRow_NEON(const uint8* src_y0, const uint8* src_y1, 3063 const uint8* src_y2, uint8* dst_sobelx, int width) { 3064 asm volatile ( 3065 ".p2align 2 \n" 3066 "1: \n" 3067 MEMACCESS(0) 3068 "vld1.8 {d0}, [%0],%5 \n" // top 3069 MEMACCESS(0) 3070 "vld1.8 {d1}, [%0],%6 \n" 3071 "vsubl.u8 q0, d0, d1 \n" 3072 MEMACCESS(1) 3073 "vld1.8 {d2}, [%1],%5 \n" // center * 2 3074 MEMACCESS(1) 3075 "vld1.8 {d3}, [%1],%6 \n" 3076 "vsubl.u8 q1, d2, d3 \n" 3077 "vadd.s16 q0, q0, q1 \n" 3078 "vadd.s16 q0, q0, q1 \n" 3079 MEMACCESS(2) 3080 "vld1.8 {d2}, [%2],%5 \n" // bottom 3081 MEMACCESS(2) 3082 "vld1.8 {d3}, [%2],%6 \n" 3083 "subs %4, %4, #8 \n" // 8 pixels 3084 "vsubl.u8 q1, d2, d3 \n" 3085 "vadd.s16 q0, q0, q1 \n" 3086 "vabs.s16 q0, q0 \n" 3087 "vqmovn.u16 d0, q0 \n" 3088 MEMACCESS(3) 3089 "vst1.8 {d0}, [%3]! \n" // store 8 sobelx 3090 "bgt 1b \n" 3091 : "+r"(src_y0), // %0 3092 "+r"(src_y1), // %1 3093 "+r"(src_y2), // %2 3094 "+r"(dst_sobelx), // %3 3095 "+r"(width) // %4 3096 : "r"(2), // %5 3097 "r"(6) // %6 3098 : "cc", "memory", "q0", "q1" // Clobber List 3099 ); 3100 } 3101 3102 // SobelY as a matrix is 3103 // -1 -2 -1 3104 // 0 0 0 3105 // 1 2 1 3106 void SobelYRow_NEON(const uint8* src_y0, const uint8* src_y1, 3107 uint8* dst_sobely, int width) { 3108 asm volatile ( 3109 ".p2align 2 \n" 3110 "1: \n" 3111 MEMACCESS(0) 3112 "vld1.8 {d0}, [%0],%4 \n" // left 3113 MEMACCESS(1) 3114 "vld1.8 {d1}, [%1],%4 \n" 3115 "vsubl.u8 q0, d0, d1 \n" 3116 MEMACCESS(0) 3117 "vld1.8 {d2}, [%0],%4 \n" // center * 2 3118 MEMACCESS(1) 3119 "vld1.8 {d3}, [%1],%4 \n" 3120 "vsubl.u8 q1, d2, d3 \n" 3121 "vadd.s16 q0, q0, q1 \n" 3122 "vadd.s16 q0, q0, q1 \n" 3123 MEMACCESS(0) 3124 "vld1.8 {d2}, [%0],%5 \n" // right 3125 MEMACCESS(1) 3126 "vld1.8 {d3}, [%1],%5 \n" 3127 "subs %3, %3, #8 \n" // 8 pixels 3128 "vsubl.u8 q1, d2, d3 \n" 3129 "vadd.s16 q0, q0, q1 \n" 3130 "vabs.s16 q0, q0 \n" 3131 "vqmovn.u16 d0, q0 \n" 3132 MEMACCESS(2) 3133 "vst1.8 {d0}, [%2]! \n" // store 8 sobely 3134 "bgt 1b \n" 3135 : "+r"(src_y0), // %0 3136 "+r"(src_y1), // %1 3137 "+r"(dst_sobely), // %2 3138 "+r"(width) // %3 3139 : "r"(1), // %4 3140 "r"(6) // %5 3141 : "cc", "memory", "q0", "q1" // Clobber List 3142 ); 3143 } 3144 #endif // __ARM_NEON__ 3145 3146 #ifdef __cplusplus 3147 } // extern "C" 3148 } // namespace libyuv 3149 #endif 3150