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