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