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