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