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