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