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