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