blob: c9423524ed0c69998f811963efdc9cc91e7b4904 [file] [log] [blame]
DRC321e0682011-05-03 08:47:43 +00001/*
2 * ARM NEON optimizations for libjpeg-turbo
3 *
4 * Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies).
5 * All rights reserved.
6 * Contact: Alexander Bokovoy <alexander.bokovoy@nokia.com>
7 *
8 * This software is provided 'as-is', without any express or implied
9 * warranty. In no event will the authors be held liable for any damages
10 * arising from the use of this software.
11 *
12 * Permission is granted to anyone to use this software for any purpose,
13 * including commercial applications, and to alter it and redistribute it
14 * freely, subject to the following restrictions:
15 *
16 * 1. The origin of this software must not be misrepresented; you must not
17 * claim that you wrote the original software. If you use this software
18 * in a product, an acknowledgment in the product documentation would be
19 * appreciated but is not required.
20 * 2. Altered source versions must be plainly marked as such, and must not be
21 * misrepresented as being the original software.
22 * 3. This notice may not be removed or altered from any source distribution.
23 */
24
25#if defined(__linux__) && defined(__ELF__)
26.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
27#endif
28
29.text
30.fpu neon
31.arch armv7a
32.object_arch armv4
DRC321e0682011-05-03 08:47:43 +000033.arm
34
DRC8c60d222011-06-17 21:12:58 +000035
36#define RESPECT_STRICT_ALIGNMENT 1
37
DRC321e0682011-05-03 08:47:43 +000038/*****************************************************************************/
39
40/* Supplementary macro for setting function attributes */
41.macro asm_function fname
DRC4346f912011-06-14 22:16:50 +000042#ifdef __APPLE__
43 .func _\fname
44 .globl _\fname
45_\fname:
46#else
47 .func \fname
48 .global \fname
DRC321e0682011-05-03 08:47:43 +000049#ifdef __ELF__
DRC4346f912011-06-14 22:16:50 +000050 .hidden \fname
51 .type \fname, %function
DRC321e0682011-05-03 08:47:43 +000052#endif
DRC4346f912011-06-14 22:16:50 +000053\fname:
54#endif
DRC321e0682011-05-03 08:47:43 +000055.endm
56
57/* Transpose a block of 4x4 coefficients in four 64-bit registers */
58.macro transpose_4x4 x0, x1, x2, x3
DRC4346f912011-06-14 22:16:50 +000059 vtrn.16 \x0, \x1
60 vtrn.16 \x2, \x3
61 vtrn.32 \x0, \x2
62 vtrn.32 \x1, \x3
DRC321e0682011-05-03 08:47:43 +000063.endm
64
65/*****************************************************************************/
66
67/*
68 * jsimd_idct_ifast_neon
69 *
70 * This function contains a fast, not so accurate integer implementation of
71 * the inverse DCT (Discrete Cosine Transform). It uses the same calculations
DRC4b024a62011-08-15 08:36:51 +000072 * and produces exactly the same output as IJG's original 'jpeg_idct_ifast'
DRC321e0682011-05-03 08:47:43 +000073 * function from jidctfst.c
74 *
DRC4b024a62011-08-15 08:36:51 +000075 * Normally 1-D AAN DCT needs 5 multiplications and 29 additions.
76 * But in ARM NEON case some extra additions are required because VQDMULH
77 * instruction can't handle the constants larger than 1. So the expressions
78 * like "x * 1.082392200" have to be converted to "x * 0.082392200 + x",
79 * which introduces an extra addition. Overall, there are 6 extra additions
80 * per 1-D IDCT pass, totalling to 5 VQDMULH and 35 VADD/VSUB instructions.
DRC321e0682011-05-03 08:47:43 +000081 */
82
83#define XFIX_1_082392200 d0[0]
84#define XFIX_1_414213562 d0[1]
85#define XFIX_1_847759065 d0[2]
86#define XFIX_2_613125930 d0[3]
87
88.balign 16
89jsimd_idct_ifast_neon_consts:
90 .short (277 * 128 - 256 * 128) /* XFIX_1_082392200 */
91 .short (362 * 128 - 256 * 128) /* XFIX_1_414213562 */
92 .short (473 * 128 - 256 * 128) /* XFIX_1_847759065 */
93 .short (669 * 128 - 512 * 128) /* XFIX_2_613125930 */
94
DRC321e0682011-05-03 08:47:43 +000095asm_function jsimd_idct_ifast_neon
96
97 DCT_TABLE .req r0
98 COEF_BLOCK .req r1
99 OUTPUT_BUF .req r2
100 OUTPUT_COL .req r3
DRC4b024a62011-08-15 08:36:51 +0000101 TMP1 .req r0
102 TMP2 .req r1
103 TMP3 .req r2
104 TMP4 .req ip
DRC321e0682011-05-03 08:47:43 +0000105
DRC4b024a62011-08-15 08:36:51 +0000106 /* Load and dequantize coefficients into NEON registers
107 * with the following allocation:
DRC321e0682011-05-03 08:47:43 +0000108 * 0 1 2 3 | 4 5 6 7
109 * ---------+--------
DRC4b024a62011-08-15 08:36:51 +0000110 * 0 | d16 | d17 ( q8 )
111 * 1 | d18 | d19 ( q9 )
112 * 2 | d20 | d21 ( q10 )
113 * 3 | d22 | d23 ( q11 )
114 * 4 | d24 | d25 ( q12 )
115 * 5 | d26 | d27 ( q13 )
116 * 6 | d28 | d29 ( q14 )
117 * 7 | d30 | d31 ( q15 )
DRC321e0682011-05-03 08:47:43 +0000118 */
DRC4b024a62011-08-15 08:36:51 +0000119 adr ip, jsimd_idct_ifast_neon_consts
120 vld1.16 {d16, d17, d18, d19}, [COEF_BLOCK, :128]!
121 vld1.16 {d0, d1, d2, d3}, [DCT_TABLE, :128]!
122 vld1.16 {d20, d21, d22, d23}, [COEF_BLOCK, :128]!
123 vmul.s16 q8, q8, q0
124 vld1.16 {d4, d5, d6, d7}, [DCT_TABLE, :128]!
125 vmul.s16 q9, q9, q1
126 vld1.16 {d24, d25, d26, d27}, [COEF_BLOCK, :128]!
127 vmul.s16 q10, q10, q2
128 vld1.16 {d0, d1, d2, d3}, [DCT_TABLE, :128]!
129 vmul.s16 q11, q11, q3
130 vld1.16 {d28, d29, d30, d31}, [COEF_BLOCK, :128]
131 vmul.s16 q12, q12, q0
132 vld1.16 {d4, d5, d6, d7}, [DCT_TABLE, :128]!
133 vmul.s16 q14, q14, q2
134 vmul.s16 q13, q13, q1
135 vld1.16 {d0}, [ip, :64] /* load constants */
136 vmul.s16 q15, q15, q3
137 vpush {d8-d13} /* save NEON registers */
138 /* 1-D IDCT, pass 1 */
139 vsub.s16 q2, q10, q14
140 vadd.s16 q14, q10, q14
141 vsub.s16 q1, q11, q13
142 vadd.s16 q13, q11, q13
143 vsub.s16 q5, q9, q15
144 vadd.s16 q15, q9, q15
145 vqdmulh.s16 q4, q2, XFIX_1_414213562
146 vqdmulh.s16 q6, q1, XFIX_2_613125930
147 vadd.s16 q3, q1, q1
148 vsub.s16 q1, q5, q1
149 vadd.s16 q10, q2, q4
150 vqdmulh.s16 q4, q1, XFIX_1_847759065
151 vsub.s16 q2, q15, q13
152 vadd.s16 q3, q3, q6
153 vqdmulh.s16 q6, q2, XFIX_1_414213562
154 vadd.s16 q1, q1, q4
155 vqdmulh.s16 q4, q5, XFIX_1_082392200
156 vsub.s16 q10, q10, q14
157 vadd.s16 q2, q2, q6
158 vsub.s16 q6, q8, q12
159 vadd.s16 q12, q8, q12
160 vadd.s16 q9, q5, q4
161 vadd.s16 q5, q6, q10
162 vsub.s16 q10, q6, q10
163 vadd.s16 q6, q15, q13
164 vadd.s16 q8, q12, q14
165 vsub.s16 q3, q6, q3
166 vsub.s16 q12, q12, q14
167 vsub.s16 q3, q3, q1
168 vsub.s16 q1, q9, q1
169 vadd.s16 q2, q3, q2
170 vsub.s16 q15, q8, q6
171 vadd.s16 q1, q1, q2
172 vadd.s16 q8, q8, q6
173 vadd.s16 q14, q5, q3
174 vsub.s16 q9, q5, q3
175 vsub.s16 q13, q10, q2
176 vadd.s16 q10, q10, q2
177 /* Transpose */
178 vtrn.16 q8, q9
179 vsub.s16 q11, q12, q1
180 vtrn.16 q14, q15
181 vadd.s16 q12, q12, q1
182 vtrn.16 q10, q11
183 vtrn.16 q12, q13
184 vtrn.32 q9, q11
185 vtrn.32 q12, q14
186 vtrn.32 q8, q10
187 vtrn.32 q13, q15
188 vswp d28, d21
189 vswp d26, d19
190 /* 1-D IDCT, pass 2 */
191 vsub.s16 q2, q10, q14
192 vswp d30, d23
193 vadd.s16 q14, q10, q14
194 vswp d24, d17
195 vsub.s16 q1, q11, q13
196 vadd.s16 q13, q11, q13
197 vsub.s16 q5, q9, q15
198 vadd.s16 q15, q9, q15
199 vqdmulh.s16 q4, q2, XFIX_1_414213562
200 vqdmulh.s16 q6, q1, XFIX_2_613125930
201 vadd.s16 q3, q1, q1
202 vsub.s16 q1, q5, q1
203 vadd.s16 q10, q2, q4
204 vqdmulh.s16 q4, q1, XFIX_1_847759065
205 vsub.s16 q2, q15, q13
206 vadd.s16 q3, q3, q6
207 vqdmulh.s16 q6, q2, XFIX_1_414213562
208 vadd.s16 q1, q1, q4
209 vqdmulh.s16 q4, q5, XFIX_1_082392200
210 vsub.s16 q10, q10, q14
211 vadd.s16 q2, q2, q6
212 vsub.s16 q6, q8, q12
213 vadd.s16 q12, q8, q12
214 vadd.s16 q9, q5, q4
215 vadd.s16 q5, q6, q10
216 vsub.s16 q10, q6, q10
217 vadd.s16 q6, q15, q13
218 vadd.s16 q8, q12, q14
219 vsub.s16 q3, q6, q3
220 vsub.s16 q12, q12, q14
221 vsub.s16 q3, q3, q1
222 vsub.s16 q1, q9, q1
223 vadd.s16 q2, q3, q2
224 vsub.s16 q15, q8, q6
225 vadd.s16 q1, q1, q2
226 vadd.s16 q8, q8, q6
227 vadd.s16 q14, q5, q3
228 vsub.s16 q9, q5, q3
229 vsub.s16 q13, q10, q2
230 vpop {d8-d13} /* restore NEON registers */
231 vadd.s16 q10, q10, q2
232 /* Transpose */
233 vtrn.16 q8, q9
234 vsub.s16 q11, q12, q1
235 vtrn.16 q14, q15
236 vadd.s16 q12, q12, q1
237 vtrn.16 q10, q11
238 vtrn.16 q12, q13
DRC321e0682011-05-03 08:47:43 +0000239 /* Descale and range limit */
DRC4b024a62011-08-15 08:36:51 +0000240 vmov.s16 q0, #(0x80 << 5)
241 vtrn.32 q9, q11
242 vtrn.32 q12, q14
243 vtrn.32 q8, q10
244 vtrn.32 q13, q15
245 vswp d24, d17
246 vswp d26, d19
247 vqadd.s16 q8, q8, q0
248 vswp d28, d21
249 vqadd.s16 q9, q9, q0
250 vswp d30, d23
251 vqadd.s16 q10, q10, q0
252 vqadd.s16 q11, q11, q0
253 /* Store results to the output buffer */
254 ldmia OUTPUT_BUF!, {TMP1, TMP2}
255 add TMP1, TMP1, OUTPUT_COL
256 add TMP2, TMP2, OUTPUT_COL
257 vqshrun.s16 d16, q8, #5
258 vqshrun.s16 d17, q9, #5
259 vqshrun.s16 d18, q10, #5
260 vqshrun.s16 d19, q11, #5
261 vst1.8 {d16}, [TMP1]
262 vqadd.s16 q12, q12, q0
263 vqadd.s16 q13, q13, q0
264 vst1.8 {d17}, [TMP2]
265 vqadd.s16 q14, q14, q0
266 vqadd.s16 q15, q15, q0
267 ldmia OUTPUT_BUF!, {TMP1, TMP2}
268 add TMP1, TMP1, OUTPUT_COL
269 add TMP2, TMP2, OUTPUT_COL
270 vst1.8 {d18}, [TMP1]
271 vqshrun.s16 d20, q12, #5
272 vqshrun.s16 d21, q13, #5
273 vst1.8 {d19}, [TMP2]
274 vqshrun.s16 d22, q14, #5
275 ldmia OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4}
276 add TMP1, TMP1, OUTPUT_COL
277 add TMP2, TMP2, OUTPUT_COL
278 add TMP3, TMP3, OUTPUT_COL
279 add TMP4, TMP4, OUTPUT_COL
280 vst1.8 {d20}, [TMP1]
281 vqshrun.s16 d23, q15, #5
282 vst1.8 {d21}, [TMP2]
283 vst1.8 {d22}, [TMP3]
284 vst1.8 {d23}, [TMP4]
DRC321e0682011-05-03 08:47:43 +0000285 bx lr
286
287 .unreq DCT_TABLE
288 .unreq COEF_BLOCK
289 .unreq OUTPUT_BUF
290 .unreq OUTPUT_COL
DRC4b024a62011-08-15 08:36:51 +0000291 .unreq TMP1
292 .unreq TMP2
293 .unreq TMP3
294 .unreq TMP4
DRC321e0682011-05-03 08:47:43 +0000295.endfunc
296
DRC321e0682011-05-03 08:47:43 +0000297/*****************************************************************************/
298
299/*
DRC8c60d222011-06-17 21:12:58 +0000300 * jsimd_idct_4x4_neon
301 *
302 * This function contains inverse-DCT code for getting reduced-size
303 * 4x4 pixels output from an 8x8 DCT block. It uses the same calculations
304 * and produces exactly the same output as IJG's original 'jpeg_idct_4x4'
305 * function from jpeg-6b (jidctred.c).
306 *
307 * NOTE: jpeg-8 has an improved implementation of 4x4 inverse-DCT, which
308 * requires much less arithmetic operations and hence should be faster.
309 * The primary purpose of this particular NEON optimized function is
310 * bit exact compatibility with jpeg-6b.
311 *
312 * TODO: a bit better instructions scheduling can be achieved by expanding
313 * idct_helper/transpose_4x4 macros and reordering instructions,
314 * but readability will suffer somewhat.
315 */
316
317#define CONST_BITS 13
318
319#define FIX_0_211164243 (1730) /* FIX(0.211164243) */
320#define FIX_0_509795579 (4176) /* FIX(0.509795579) */
321#define FIX_0_601344887 (4926) /* FIX(0.601344887) */
322#define FIX_0_720959822 (5906) /* FIX(0.720959822) */
323#define FIX_0_765366865 (6270) /* FIX(0.765366865) */
324#define FIX_0_850430095 (6967) /* FIX(0.850430095) */
325#define FIX_0_899976223 (7373) /* FIX(0.899976223) */
326#define FIX_1_061594337 (8697) /* FIX(1.061594337) */
327#define FIX_1_272758580 (10426) /* FIX(1.272758580) */
328#define FIX_1_451774981 (11893) /* FIX(1.451774981) */
329#define FIX_1_847759065 (15137) /* FIX(1.847759065) */
330#define FIX_2_172734803 (17799) /* FIX(2.172734803) */
331#define FIX_2_562915447 (20995) /* FIX(2.562915447) */
332#define FIX_3_624509785 (29692) /* FIX(3.624509785) */
333
334.balign 16
335jsimd_idct_4x4_neon_consts:
336 .short FIX_1_847759065 /* d0[0] */
337 .short -FIX_0_765366865 /* d0[1] */
338 .short -FIX_0_211164243 /* d0[2] */
339 .short FIX_1_451774981 /* d0[3] */
340 .short -FIX_2_172734803 /* d1[0] */
341 .short FIX_1_061594337 /* d1[1] */
342 .short -FIX_0_509795579 /* d1[2] */
343 .short -FIX_0_601344887 /* d1[3] */
344 .short FIX_0_899976223 /* d2[0] */
345 .short FIX_2_562915447 /* d2[1] */
346 .short 1 << (CONST_BITS+1) /* d2[2] */
347 .short 0 /* d2[3] */
348
349.macro idct_helper x4, x6, x8, x10, x12, x14, x16, shift, y26, y27, y28, y29
350 vmull.s16 q14, \x4, d2[2]
351 vmlal.s16 q14, \x8, d0[0]
352 vmlal.s16 q14, \x14, d0[1]
353
354 vmull.s16 q13, \x16, d1[2]
355 vmlal.s16 q13, \x12, d1[3]
356 vmlal.s16 q13, \x10, d2[0]
357 vmlal.s16 q13, \x6, d2[1]
358
359 vmull.s16 q15, \x4, d2[2]
360 vmlsl.s16 q15, \x8, d0[0]
361 vmlsl.s16 q15, \x14, d0[1]
362
363 vmull.s16 q12, \x16, d0[2]
364 vmlal.s16 q12, \x12, d0[3]
365 vmlal.s16 q12, \x10, d1[0]
366 vmlal.s16 q12, \x6, d1[1]
367
368 vadd.s32 q10, q14, q13
369 vsub.s32 q14, q14, q13
370
371.if \shift > 16
372 vrshr.s32 q10, q10, #\shift
373 vrshr.s32 q14, q14, #\shift
374 vmovn.s32 \y26, q10
375 vmovn.s32 \y29, q14
376.else
377 vrshrn.s32 \y26, q10, #\shift
378 vrshrn.s32 \y29, q14, #\shift
379.endif
380
381 vadd.s32 q10, q15, q12
382 vsub.s32 q15, q15, q12
383
384.if \shift > 16
385 vrshr.s32 q10, q10, #\shift
386 vrshr.s32 q15, q15, #\shift
387 vmovn.s32 \y27, q10
388 vmovn.s32 \y28, q15
389.else
390 vrshrn.s32 \y27, q10, #\shift
391 vrshrn.s32 \y28, q15, #\shift
392.endif
393
394.endm
395
396asm_function jsimd_idct_4x4_neon
397
398 DCT_TABLE .req r0
399 COEF_BLOCK .req r1
400 OUTPUT_BUF .req r2
401 OUTPUT_COL .req r3
402 TMP1 .req r0
403 TMP2 .req r1
404 TMP3 .req r2
405 TMP4 .req ip
406
407 vpush {d8-d15}
408
409 /* Load constants (d3 is just used for padding) */
410 adr TMP4, jsimd_idct_4x4_neon_consts
411 vld1.16 {d0, d1, d2, d3}, [TMP4, :128]
412
413 /* Load all COEF_BLOCK into NEON registers with the following allocation:
414 * 0 1 2 3 | 4 5 6 7
415 * ---------+--------
416 * 0 | d4 | d5
417 * 1 | d6 | d7
418 * 2 | d8 | d9
419 * 3 | d10 | d11
420 * 4 | - | -
421 * 5 | d12 | d13
422 * 6 | d14 | d15
423 * 7 | d16 | d17
424 */
425 vld1.16 {d4, d5, d6, d7}, [COEF_BLOCK, :128]!
426 vld1.16 {d8, d9, d10, d11}, [COEF_BLOCK, :128]!
427 add COEF_BLOCK, COEF_BLOCK, #16
428 vld1.16 {d12, d13, d14, d15}, [COEF_BLOCK, :128]!
429 vld1.16 {d16, d17}, [COEF_BLOCK, :128]!
430 /* dequantize */
431 vld1.16 {d18, d19, d20, d21}, [DCT_TABLE, :128]!
432 vmul.s16 q2, q2, q9
433 vld1.16 {d22, d23, d24, d25}, [DCT_TABLE, :128]!
434 vmul.s16 q3, q3, q10
435 vmul.s16 q4, q4, q11
436 add DCT_TABLE, DCT_TABLE, #16
437 vld1.16 {d26, d27, d28, d29}, [DCT_TABLE, :128]!
438 vmul.s16 q5, q5, q12
439 vmul.s16 q6, q6, q13
440 vld1.16 {d30, d31}, [DCT_TABLE, :128]!
441 vmul.s16 q7, q7, q14
442 vmul.s16 q8, q8, q15
443
444 /* Pass 1 */
445 idct_helper d4, d6, d8, d10, d12, d14, d16, 12, d4, d6, d8, d10
446 transpose_4x4 d4, d6, d8, d10
447 idct_helper d5, d7, d9, d11, d13, d15, d17, 12, d5, d7, d9, d11
448 transpose_4x4 d5, d7, d9, d11
449
450 /* Pass 2 */
451 idct_helper d4, d6, d8, d10, d7, d9, d11, 19, d26, d27, d28, d29
452 transpose_4x4 d26, d27, d28, d29
453
454 /* Range limit */
455 vmov.u16 q15, #0x80
456 vadd.s16 q13, q13, q15
457 vadd.s16 q14, q14, q15
458 vqmovun.s16 d26, q13
459 vqmovun.s16 d27, q14
460
461 /* Store results to the output buffer */
462 ldmia OUTPUT_BUF, {TMP1, TMP2, TMP3, TMP4}
463 add TMP1, TMP1, OUTPUT_COL
464 add TMP2, TMP2, OUTPUT_COL
465 add TMP3, TMP3, OUTPUT_COL
466 add TMP4, TMP4, OUTPUT_COL
467
468#if defined(__ARMEL__) && !RESPECT_STRICT_ALIGNMENT
469 /* We can use much less instructions on little endian systems if the
470 * OS kernel is not configured to trap unaligned memory accesses
471 */
472 vst1.32 {d26[0]}, [TMP1]!
473 vst1.32 {d27[0]}, [TMP3]!
474 vst1.32 {d26[1]}, [TMP2]!
475 vst1.32 {d27[1]}, [TMP4]!
476#else
477 vst1.8 {d26[0]}, [TMP1]!
478 vst1.8 {d27[0]}, [TMP3]!
479 vst1.8 {d26[1]}, [TMP1]!
480 vst1.8 {d27[1]}, [TMP3]!
481 vst1.8 {d26[2]}, [TMP1]!
482 vst1.8 {d27[2]}, [TMP3]!
483 vst1.8 {d26[3]}, [TMP1]!
484 vst1.8 {d27[3]}, [TMP3]!
485
486 vst1.8 {d26[4]}, [TMP2]!
487 vst1.8 {d27[4]}, [TMP4]!
488 vst1.8 {d26[5]}, [TMP2]!
489 vst1.8 {d27[5]}, [TMP4]!
490 vst1.8 {d26[6]}, [TMP2]!
491 vst1.8 {d27[6]}, [TMP4]!
492 vst1.8 {d26[7]}, [TMP2]!
493 vst1.8 {d27[7]}, [TMP4]!
494#endif
495
496 vpop {d8-d15}
497 bx lr
498
499 .unreq DCT_TABLE
500 .unreq COEF_BLOCK
501 .unreq OUTPUT_BUF
502 .unreq OUTPUT_COL
503 .unreq TMP1
504 .unreq TMP2
505 .unreq TMP3
506 .unreq TMP4
507.endfunc
508
509.purgem idct_helper
510
511/*****************************************************************************/
512
513/*
514 * jsimd_idct_2x2_neon
515 *
516 * This function contains inverse-DCT code for getting reduced-size
517 * 2x2 pixels output from an 8x8 DCT block. It uses the same calculations
518 * and produces exactly the same output as IJG's original 'jpeg_idct_2x2'
519 * function from jpeg-6b (jidctred.c).
520 *
521 * NOTE: jpeg-8 has an improved implementation of 2x2 inverse-DCT, which
522 * requires much less arithmetic operations and hence should be faster.
523 * The primary purpose of this particular NEON optimized function is
524 * bit exact compatibility with jpeg-6b.
525 */
526
527.balign 8
528jsimd_idct_2x2_neon_consts:
529 .short -FIX_0_720959822 /* d0[0] */
530 .short FIX_0_850430095 /* d0[1] */
531 .short -FIX_1_272758580 /* d0[2] */
532 .short FIX_3_624509785 /* d0[3] */
533
534.macro idct_helper x4, x6, x10, x12, x16, shift, y26, y27
535 vshll.s16 q14, \x4, #15
536 vmull.s16 q13, \x6, d0[3]
537 vmlal.s16 q13, \x10, d0[2]
538 vmlal.s16 q13, \x12, d0[1]
539 vmlal.s16 q13, \x16, d0[0]
540
541 vadd.s32 q10, q14, q13
542 vsub.s32 q14, q14, q13
543
544.if \shift > 16
545 vrshr.s32 q10, q10, #\shift
546 vrshr.s32 q14, q14, #\shift
547 vmovn.s32 \y26, q10
548 vmovn.s32 \y27, q14
549.else
550 vrshrn.s32 \y26, q10, #\shift
551 vrshrn.s32 \y27, q14, #\shift
552.endif
553
554.endm
555
556asm_function jsimd_idct_2x2_neon
557
558 DCT_TABLE .req r0
559 COEF_BLOCK .req r1
560 OUTPUT_BUF .req r2
561 OUTPUT_COL .req r3
562 TMP1 .req r0
563 TMP2 .req ip
564
565 vpush {d8-d15}
566
567 /* Load constants */
568 adr TMP2, jsimd_idct_2x2_neon_consts
569 vld1.16 {d0}, [TMP2, :64]
570
571 /* Load all COEF_BLOCK into NEON registers with the following allocation:
572 * 0 1 2 3 | 4 5 6 7
573 * ---------+--------
574 * 0 | d4 | d5
575 * 1 | d6 | d7
576 * 2 | - | -
577 * 3 | d10 | d11
578 * 4 | - | -
579 * 5 | d12 | d13
580 * 6 | - | -
581 * 7 | d16 | d17
582 */
583 vld1.16 {d4, d5, d6, d7}, [COEF_BLOCK, :128]!
584 add COEF_BLOCK, COEF_BLOCK, #16
585 vld1.16 {d10, d11}, [COEF_BLOCK, :128]!
586 add COEF_BLOCK, COEF_BLOCK, #16
587 vld1.16 {d12, d13}, [COEF_BLOCK, :128]!
588 add COEF_BLOCK, COEF_BLOCK, #16
589 vld1.16 {d16, d17}, [COEF_BLOCK, :128]!
590 /* Dequantize */
591 vld1.16 {d18, d19, d20, d21}, [DCT_TABLE, :128]!
592 vmul.s16 q2, q2, q9
593 vmul.s16 q3, q3, q10
594 add DCT_TABLE, DCT_TABLE, #16
595 vld1.16 {d24, d25}, [DCT_TABLE, :128]!
596 vmul.s16 q5, q5, q12
597 add DCT_TABLE, DCT_TABLE, #16
598 vld1.16 {d26, d27}, [DCT_TABLE, :128]!
599 vmul.s16 q6, q6, q13
600 add DCT_TABLE, DCT_TABLE, #16
601 vld1.16 {d30, d31}, [DCT_TABLE, :128]!
602 vmul.s16 q8, q8, q15
603
604 /* Pass 1 */
605#if 0
606 idct_helper d4, d6, d10, d12, d16, 13, d4, d6
607 transpose_4x4 d4, d6, d8, d10
608 idct_helper d5, d7, d11, d13, d17, 13, d5, d7
609 transpose_4x4 d5, d7, d9, d11
610#else
611 vmull.s16 q13, d6, d0[3]
612 vmlal.s16 q13, d10, d0[2]
613 vmlal.s16 q13, d12, d0[1]
614 vmlal.s16 q13, d16, d0[0]
615 vmull.s16 q12, d7, d0[3]
616 vmlal.s16 q12, d11, d0[2]
617 vmlal.s16 q12, d13, d0[1]
618 vmlal.s16 q12, d17, d0[0]
619 vshll.s16 q14, d4, #15
620 vshll.s16 q15, d5, #15
621 vadd.s32 q10, q14, q13
622 vsub.s32 q14, q14, q13
623 vrshrn.s32 d4, q10, #13
624 vrshrn.s32 d6, q14, #13
625 vadd.s32 q10, q15, q12
626 vsub.s32 q14, q15, q12
627 vrshrn.s32 d5, q10, #13
628 vrshrn.s32 d7, q14, #13
629 vtrn.16 q2, q3
630 vtrn.32 q3, q5
631#endif
632
633 /* Pass 2 */
634 idct_helper d4, d6, d10, d7, d11, 20, d26, d27
635
636 /* Range limit */
637 vmov.u16 q15, #0x80
638 vadd.s16 q13, q13, q15
639 vqmovun.s16 d26, q13
640 vqmovun.s16 d27, q13
641
642 /* Store results to the output buffer */
643 ldmia OUTPUT_BUF, {TMP1, TMP2}
644 add TMP1, TMP1, OUTPUT_COL
645 add TMP2, TMP2, OUTPUT_COL
646
647 vst1.8 {d26[0]}, [TMP1]!
648 vst1.8 {d27[4]}, [TMP1]!
649 vst1.8 {d26[1]}, [TMP2]!
650 vst1.8 {d27[5]}, [TMP2]!
651
652 vpop {d8-d15}
653 bx lr
654
655 .unreq DCT_TABLE
656 .unreq COEF_BLOCK
657 .unreq OUTPUT_BUF
658 .unreq OUTPUT_COL
659 .unreq TMP1
660 .unreq TMP2
661.endfunc
662
663.purgem idct_helper
664
665/*****************************************************************************/
666
667/*
DRC321e0682011-05-03 08:47:43 +0000668 * jsimd_ycc_extrgb_convert_neon
669 * jsimd_ycc_extbgr_convert_neon
670 * jsimd_ycc_extrgbx_convert_neon
671 * jsimd_ycc_extbgrx_convert_neon
672 * jsimd_ycc_extxbgr_convert_neon
673 * jsimd_ycc_extxrgb_convert_neon
674 *
675 * Colorspace conversion YCbCr -> RGB
676 */
677
DRC321e0682011-05-03 08:47:43 +0000678
679.macro do_load size
DRC4346f912011-06-14 22:16:50 +0000680 .if \size == 8
DRC321e0682011-05-03 08:47:43 +0000681 vld1.8 {d4}, [U]!
682 vld1.8 {d5}, [V]!
683 vld1.8 {d0}, [Y]!
684 pld [Y, #64]
685 pld [U, #64]
686 pld [V, #64]
DRC4346f912011-06-14 22:16:50 +0000687 .elseif \size == 4
DRC321e0682011-05-03 08:47:43 +0000688 vld1.8 {d4[0]}, [U]!
689 vld1.8 {d4[1]}, [U]!
690 vld1.8 {d4[2]}, [U]!
691 vld1.8 {d4[3]}, [U]!
692 vld1.8 {d5[0]}, [V]!
693 vld1.8 {d5[1]}, [V]!
694 vld1.8 {d5[2]}, [V]!
695 vld1.8 {d5[3]}, [V]!
696 vld1.8 {d0[0]}, [Y]!
697 vld1.8 {d0[1]}, [Y]!
698 vld1.8 {d0[2]}, [Y]!
699 vld1.8 {d0[3]}, [Y]!
DRC4346f912011-06-14 22:16:50 +0000700 .elseif \size == 2
DRC321e0682011-05-03 08:47:43 +0000701 vld1.8 {d4[4]}, [U]!
702 vld1.8 {d4[5]}, [U]!
703 vld1.8 {d5[4]}, [V]!
704 vld1.8 {d5[5]}, [V]!
705 vld1.8 {d0[4]}, [Y]!
706 vld1.8 {d0[5]}, [Y]!
DRC4346f912011-06-14 22:16:50 +0000707 .elseif \size == 1
DRC321e0682011-05-03 08:47:43 +0000708 vld1.8 {d4[6]}, [U]!
709 vld1.8 {d5[6]}, [V]!
710 vld1.8 {d0[6]}, [Y]!
711 .else
712 .error unsupported macroblock size
713 .endif
714.endm
715
716.macro do_store bpp, size
DRC4346f912011-06-14 22:16:50 +0000717 .if \bpp == 24
718 .if \size == 8
DRC321e0682011-05-03 08:47:43 +0000719 vst3.8 {d10, d11, d12}, [RGB]!
DRC4346f912011-06-14 22:16:50 +0000720 .elseif \size == 4
DRC321e0682011-05-03 08:47:43 +0000721 vst3.8 {d10[0], d11[0], d12[0]}, [RGB]!
722 vst3.8 {d10[1], d11[1], d12[1]}, [RGB]!
723 vst3.8 {d10[2], d11[2], d12[2]}, [RGB]!
724 vst3.8 {d10[3], d11[3], d12[3]}, [RGB]!
DRC4346f912011-06-14 22:16:50 +0000725 .elseif \size == 2
DRC321e0682011-05-03 08:47:43 +0000726 vst3.8 {d10[4], d11[4], d12[4]}, [RGB]!
727 vst3.8 {d10[5], d11[5], d12[5]}, [RGB]!
DRC4346f912011-06-14 22:16:50 +0000728 .elseif \size == 1
DRC321e0682011-05-03 08:47:43 +0000729 vst3.8 {d10[6], d11[6], d12[6]}, [RGB]!
730 .else
731 .error unsupported macroblock size
732 .endif
DRC4346f912011-06-14 22:16:50 +0000733 .elseif \bpp == 32
734 .if \size == 8
DRC321e0682011-05-03 08:47:43 +0000735 vst4.8 {d10, d11, d12, d13}, [RGB]!
DRC4346f912011-06-14 22:16:50 +0000736 .elseif \size == 4
DRC321e0682011-05-03 08:47:43 +0000737 vst4.8 {d10[0], d11[0], d12[0], d13[0]}, [RGB]!
738 vst4.8 {d10[1], d11[1], d12[1], d13[1]}, [RGB]!
739 vst4.8 {d10[2], d11[2], d12[2], d13[2]}, [RGB]!
740 vst4.8 {d10[3], d11[3], d12[3], d13[3]}, [RGB]!
DRC4346f912011-06-14 22:16:50 +0000741 .elseif \size == 2
DRC321e0682011-05-03 08:47:43 +0000742 vst4.8 {d10[4], d11[4], d12[4], d13[4]}, [RGB]!
743 vst4.8 {d10[5], d11[5], d12[5], d13[5]}, [RGB]!
DRC4346f912011-06-14 22:16:50 +0000744 .elseif \size == 1
DRC321e0682011-05-03 08:47:43 +0000745 vst4.8 {d10[6], d11[6], d12[6], d13[6]}, [RGB]!
746 .else
747 .error unsupported macroblock size
748 .endif
749 .else
750 .error unsupported bpp
751 .endif
752.endm
753
754.macro generate_jsimd_ycc_rgb_convert_neon colorid, bpp, r_offs, g_offs, b_offs
755
756.macro do_yuv_to_rgb
757 vaddw.u8 q3, q1, d4 /* q3 = u - 128 */
758 vaddw.u8 q4, q1, d5 /* q2 = v - 128 */
759 vmull.s16 q10, d6, d1[1] /* multiply by -11277 */
760 vmlal.s16 q10, d8, d1[2] /* multiply by -23401 */
761 vmull.s16 q11, d7, d1[1] /* multiply by -11277 */
762 vmlal.s16 q11, d9, d1[2] /* multiply by -23401 */
763 vmull.s16 q12, d8, d1[0] /* multiply by 22971 */
764 vmull.s16 q13, d9, d1[0] /* multiply by 22971 */
765 vmull.s16 q14, d6, d1[3] /* multiply by 29033 */
766 vmull.s16 q15, d7, d1[3] /* multiply by 29033 */
767 vrshrn.s32 d20, q10, #15
768 vrshrn.s32 d21, q11, #15
769 vrshrn.s32 d24, q12, #14
770 vrshrn.s32 d25, q13, #14
771 vrshrn.s32 d28, q14, #14
772 vrshrn.s32 d29, q15, #14
773 vaddw.u8 q10, q10, d0
774 vaddw.u8 q12, q12, d0
775 vaddw.u8 q14, q14, d0
DRC4346f912011-06-14 22:16:50 +0000776 vqmovun.s16 d1\g_offs, q10
777 vqmovun.s16 d1\r_offs, q12
778 vqmovun.s16 d1\b_offs, q14
DRC321e0682011-05-03 08:47:43 +0000779.endm
780
DRC4346f912011-06-14 22:16:50 +0000781/* Apple gas crashes on adrl, work around that by using adr.
782 * But this requires a copy of these constants for each function.
783 */
784
785.balign 16
786jsimd_ycc_\colorid\()_neon_consts:
787 .short 0, 0, 0, 0
788 .short 22971, -11277, -23401, 29033
789 .short -128, -128, -128, -128
790 .short -128, -128, -128, -128
791
792asm_function jsimd_ycc_\colorid\()_convert_neon
DRC321e0682011-05-03 08:47:43 +0000793 OUTPUT_WIDTH .req r0
794 INPUT_BUF .req r1
795 INPUT_ROW .req r2
796 OUTPUT_BUF .req r3
797 NUM_ROWS .req r4
798
799 INPUT_BUF0 .req r5
800 INPUT_BUF1 .req r6
801 INPUT_BUF2 .req INPUT_BUF
802
803 RGB .req r7
804 Y .req r8
805 U .req r9
806 V .req r10
807 N .req ip
808
809 /* Load constants to d1, d2, d3 (d0 is just used for padding) */
DRC4346f912011-06-14 22:16:50 +0000810 adr ip, jsimd_ycc_\colorid\()_neon_consts
DRC321e0682011-05-03 08:47:43 +0000811 vld1.16 {d0, d1, d2, d3}, [ip, :128]
812
813 /* Save ARM registers and handle input arguments */
814 push {r4, r5, r6, r7, r8, r9, r10, lr}
815 ldr NUM_ROWS, [sp, #(4 * 8)]
816 ldr INPUT_BUF0, [INPUT_BUF]
817 ldr INPUT_BUF1, [INPUT_BUF, #4]
818 ldr INPUT_BUF2, [INPUT_BUF, #8]
819 .unreq INPUT_BUF
820
821 /* Save NEON registers */
822 vpush {d8-d15}
823
824 /* Initially set d10, d11, d12, d13 to 0xFF */
825 vmov.u8 q5, #255
826 vmov.u8 q6, #255
827
828 /* Outer loop over scanlines */
829 cmp NUM_ROWS, #1
830 blt 9f
8310:
832 ldr Y, [INPUT_BUF0, INPUT_ROW, lsl #2]
833 ldr U, [INPUT_BUF1, INPUT_ROW, lsl #2]
834 mov N, OUTPUT_WIDTH
835 ldr V, [INPUT_BUF2, INPUT_ROW, lsl #2]
836 add INPUT_ROW, INPUT_ROW, #1
837 ldr RGB, [OUTPUT_BUF], #4
838
839 /* Inner loop over pixels */
840 subs N, N, #8
841 blt 2f
8421:
843 do_load 8
844 do_yuv_to_rgb
DRC4346f912011-06-14 22:16:50 +0000845 do_store \bpp, 8
DRC321e0682011-05-03 08:47:43 +0000846 subs N, N, #8
847 bge 1b
848 tst N, #7
849 beq 8f
8502:
851 tst N, #4
852 beq 3f
853 do_load 4
8543:
855 tst N, #2
856 beq 4f
857 do_load 2
8584:
859 tst N, #1
860 beq 5f
861 do_load 1
8625:
863 do_yuv_to_rgb
864 tst N, #4
865 beq 6f
DRC4346f912011-06-14 22:16:50 +0000866 do_store \bpp, 4
DRC321e0682011-05-03 08:47:43 +00008676:
868 tst N, #2
869 beq 7f
DRC4346f912011-06-14 22:16:50 +0000870 do_store \bpp, 2
DRC321e0682011-05-03 08:47:43 +00008717:
872 tst N, #1
873 beq 8f
DRC4346f912011-06-14 22:16:50 +0000874 do_store \bpp, 1
DRC321e0682011-05-03 08:47:43 +00008758:
876 subs NUM_ROWS, NUM_ROWS, #1
877 bgt 0b
8789:
879 /* Restore all registers and return */
880 vpop {d8-d15}
881 pop {r4, r5, r6, r7, r8, r9, r10, pc}
882
883 .unreq OUTPUT_WIDTH
884 .unreq INPUT_ROW
885 .unreq OUTPUT_BUF
886 .unreq NUM_ROWS
887 .unreq INPUT_BUF0
888 .unreq INPUT_BUF1
889 .unreq INPUT_BUF2
890 .unreq RGB
891 .unreq Y
892 .unreq U
893 .unreq V
894 .unreq N
895.endfunc
896
897.purgem do_yuv_to_rgb
898
899.endm
900
901/*--------------------------------- id ----- bpp R G B */
902generate_jsimd_ycc_rgb_convert_neon extrgb, 24, 0, 1, 2
903generate_jsimd_ycc_rgb_convert_neon extbgr, 24, 2, 1, 0
904generate_jsimd_ycc_rgb_convert_neon extrgbx, 32, 0, 1, 2
905generate_jsimd_ycc_rgb_convert_neon extbgrx, 32, 2, 1, 0
906generate_jsimd_ycc_rgb_convert_neon extxbgr, 32, 3, 2, 1
907generate_jsimd_ycc_rgb_convert_neon extxrgb, 32, 1, 2, 3
908
909.purgem do_load
910.purgem do_store
911
912/*****************************************************************************/
DRCb7400542011-08-10 23:31:13 +0000913
914/*
DRC7a9376c2011-08-12 19:27:20 +0000915 * jsimd_extrgb_ycc_convert_neon
916 * jsimd_extbgr_ycc_convert_neon
917 * jsimd_extrgbx_ycc_convert_neon
918 * jsimd_extbgrx_ycc_convert_neon
919 * jsimd_extxbgr_ycc_convert_neon
920 * jsimd_extxrgb_ycc_convert_neon
921 *
922 * Colorspace conversion RGB -> YCbCr
923 */
924
925.macro do_store size
926 .if \size == 8
927 vst1.8 {d20}, [Y]!
928 vst1.8 {d21}, [U]!
929 vst1.8 {d22}, [V]!
930 .elseif \size == 4
931 vst1.8 {d20[0]}, [Y]!
932 vst1.8 {d20[1]}, [Y]!
933 vst1.8 {d20[2]}, [Y]!
934 vst1.8 {d20[3]}, [Y]!
935 vst1.8 {d21[0]}, [U]!
936 vst1.8 {d21[1]}, [U]!
937 vst1.8 {d21[2]}, [U]!
938 vst1.8 {d21[3]}, [U]!
939 vst1.8 {d22[0]}, [V]!
940 vst1.8 {d22[1]}, [V]!
941 vst1.8 {d22[2]}, [V]!
942 vst1.8 {d22[3]}, [V]!
943 .elseif \size == 2
944 vst1.8 {d20[4]}, [Y]!
945 vst1.8 {d20[5]}, [Y]!
946 vst1.8 {d21[4]}, [U]!
947 vst1.8 {d21[5]}, [U]!
948 vst1.8 {d22[4]}, [V]!
949 vst1.8 {d22[5]}, [V]!
950 .elseif \size == 1
951 vst1.8 {d20[6]}, [Y]!
952 vst1.8 {d21[6]}, [U]!
953 vst1.8 {d22[6]}, [V]!
954 .else
955 .error unsupported macroblock size
956 .endif
957.endm
958
959.macro do_load bpp, size
960 .if \bpp == 24
961 .if \size == 8
962 vld3.8 {d10, d11, d12}, [RGB]!
963 pld [RGB, #128]
964 .elseif \size == 4
965 vld3.8 {d10[0], d11[0], d12[0]}, [RGB]!
966 vld3.8 {d10[1], d11[1], d12[1]}, [RGB]!
967 vld3.8 {d10[2], d11[2], d12[2]}, [RGB]!
968 vld3.8 {d10[3], d11[3], d12[3]}, [RGB]!
969 .elseif \size == 2
970 vld3.8 {d10[4], d11[4], d12[4]}, [RGB]!
971 vld3.8 {d10[5], d11[5], d12[5]}, [RGB]!
972 .elseif \size == 1
973 vld3.8 {d10[6], d11[6], d12[6]}, [RGB]!
974 .else
975 .error unsupported macroblock size
976 .endif
977 .elseif \bpp == 32
978 .if \size == 8
979 vld4.8 {d10, d11, d12, d13}, [RGB]!
980 pld [RGB, #128]
981 .elseif \size == 4
982 vld4.8 {d10[0], d11[0], d12[0], d13[0]}, [RGB]!
983 vld4.8 {d10[1], d11[1], d12[1], d13[1]}, [RGB]!
984 vld4.8 {d10[2], d11[2], d12[2], d13[2]}, [RGB]!
985 vld4.8 {d10[3], d11[3], d12[3], d13[3]}, [RGB]!
986 .elseif \size == 2
987 vld4.8 {d10[4], d11[4], d12[4], d13[4]}, [RGB]!
988 vld4.8 {d10[5], d11[5], d12[5], d13[5]}, [RGB]!
989 .elseif \size == 1
990 vld4.8 {d10[6], d11[6], d12[6], d13[6]}, [RGB]!
991 .else
992 .error unsupported macroblock size
993 .endif
994 .else
995 .error unsupported bpp
996 .endif
997.endm
998
999.macro generate_jsimd_rgb_ycc_convert_neon colorid, bpp, r_offs, g_offs, b_offs
1000
1001/*
1002 * 2 stage pipelined RGB->YCbCr conversion
1003 */
1004
1005.macro do_rgb_to_yuv_stage1
1006 vmovl.u8 q2, d1\r_offs /* r = { d4, d5 } */
1007 vmovl.u8 q3, d1\g_offs /* g = { d6, d7 } */
1008 vmovl.u8 q4, d1\b_offs /* b = { d8, d9 } */
1009 vmull.u16 q7, d4, d0[0]
1010 vmlal.u16 q7, d6, d0[1]
1011 vmlal.u16 q7, d8, d0[2]
1012 vmull.u16 q8, d5, d0[0]
1013 vmlal.u16 q8, d7, d0[1]
1014 vmlal.u16 q8, d9, d0[2]
1015 vrev64.32 q9, q1
1016 vrev64.32 q13, q1
1017 vmlsl.u16 q9, d4, d0[3]
1018 vmlsl.u16 q9, d6, d1[0]
1019 vmlal.u16 q9, d8, d1[1]
1020 vmlsl.u16 q13, d5, d0[3]
1021 vmlsl.u16 q13, d7, d1[0]
1022 vmlal.u16 q13, d9, d1[1]
1023 vrev64.32 q14, q1
1024 vrev64.32 q15, q1
1025 vmlal.u16 q14, d4, d1[1]
1026 vmlsl.u16 q14, d6, d1[2]
1027 vmlsl.u16 q14, d8, d1[3]
1028 vmlal.u16 q15, d5, d1[1]
1029 vmlsl.u16 q15, d7, d1[2]
1030 vmlsl.u16 q15, d9, d1[3]
1031.endm
1032
1033.macro do_rgb_to_yuv_stage2
1034 vrshrn.u32 d20, q7, #16
1035 vrshrn.u32 d21, q8, #16
1036 vshrn.u32 d22, q9, #16
1037 vshrn.u32 d23, q13, #16
1038 vshrn.u32 d24, q14, #16
1039 vshrn.u32 d25, q15, #16
1040 vmovn.u16 d20, q10 /* d20 = y */
1041 vmovn.u16 d21, q11 /* d21 = u */
1042 vmovn.u16 d22, q12 /* d22 = v */
1043.endm
1044
1045.macro do_rgb_to_yuv
1046 do_rgb_to_yuv_stage1
1047 do_rgb_to_yuv_stage2
1048.endm
1049
1050.macro do_rgb_to_yuv_stage2_store_load_stage1
1051 vrshrn.u32 d20, q7, #16
1052 vrshrn.u32 d21, q8, #16
1053 vshrn.u32 d22, q9, #16
1054 vrev64.32 q9, q1
1055 vshrn.u32 d23, q13, #16
1056 vrev64.32 q13, q1
1057 vshrn.u32 d24, q14, #16
1058 vshrn.u32 d25, q15, #16
1059 do_load \bpp, 8
1060 vmovn.u16 d20, q10 /* d20 = y */
1061 vmovl.u8 q2, d1\r_offs /* r = { d4, d5 } */
1062 vmovn.u16 d21, q11 /* d21 = u */
1063 vmovl.u8 q3, d1\g_offs /* g = { d6, d7 } */
1064 vmovn.u16 d22, q12 /* d22 = v */
1065 vmovl.u8 q4, d1\b_offs /* b = { d8, d9 } */
1066 vmull.u16 q7, d4, d0[0]
1067 vmlal.u16 q7, d6, d0[1]
1068 vmlal.u16 q7, d8, d0[2]
1069 vst1.8 {d20}, [Y]!
1070 vmull.u16 q8, d5, d0[0]
1071 vmlal.u16 q8, d7, d0[1]
1072 vmlal.u16 q8, d9, d0[2]
1073 vmlsl.u16 q9, d4, d0[3]
1074 vmlsl.u16 q9, d6, d1[0]
1075 vmlal.u16 q9, d8, d1[1]
1076 vst1.8 {d21}, [U]!
1077 vmlsl.u16 q13, d5, d0[3]
1078 vmlsl.u16 q13, d7, d1[0]
1079 vmlal.u16 q13, d9, d1[1]
1080 vrev64.32 q14, q1
1081 vrev64.32 q15, q1
1082 vmlal.u16 q14, d4, d1[1]
1083 vmlsl.u16 q14, d6, d1[2]
1084 vmlsl.u16 q14, d8, d1[3]
1085 vst1.8 {d22}, [V]!
1086 vmlal.u16 q15, d5, d1[1]
1087 vmlsl.u16 q15, d7, d1[2]
1088 vmlsl.u16 q15, d9, d1[3]
1089.endm
1090
1091.balign 16
1092jsimd_\colorid\()_ycc_neon_consts:
1093 .short 19595, 38470, 7471, 11059
1094 .short 21709, 32768, 27439, 5329
1095 .short 32767, 128, 32767, 128
1096 .short 32767, 128, 32767, 128
1097
1098asm_function jsimd_\colorid\()_ycc_convert_neon
1099 OUTPUT_WIDTH .req r0
1100 INPUT_BUF .req r1
1101 OUTPUT_BUF .req r2
1102 OUTPUT_ROW .req r3
1103 NUM_ROWS .req r4
1104
1105 OUTPUT_BUF0 .req r5
1106 OUTPUT_BUF1 .req r6
1107 OUTPUT_BUF2 .req OUTPUT_BUF
1108
1109 RGB .req r7
1110 Y .req r8
1111 U .req r9
1112 V .req r10
1113 N .req ip
1114
1115 /* Load constants to d0, d1, d2, d3 */
1116 adr ip, jsimd_\colorid\()_ycc_neon_consts
1117 vld1.16 {d0, d1, d2, d3}, [ip, :128]
1118
1119 /* Save ARM registers and handle input arguments */
1120 push {r4, r5, r6, r7, r8, r9, r10, lr}
1121 ldr NUM_ROWS, [sp, #(4 * 8)]
1122 ldr OUTPUT_BUF0, [OUTPUT_BUF]
1123 ldr OUTPUT_BUF1, [OUTPUT_BUF, #4]
1124 ldr OUTPUT_BUF2, [OUTPUT_BUF, #8]
1125 .unreq OUTPUT_BUF
1126
1127 /* Save NEON registers */
1128 vpush {d8-d15}
1129
1130 /* Outer loop over scanlines */
1131 cmp NUM_ROWS, #1
1132 blt 9f
11330:
1134 ldr Y, [OUTPUT_BUF0, OUTPUT_ROW, lsl #2]
1135 ldr U, [OUTPUT_BUF1, OUTPUT_ROW, lsl #2]
1136 mov N, OUTPUT_WIDTH
1137 ldr V, [OUTPUT_BUF2, OUTPUT_ROW, lsl #2]
1138 add OUTPUT_ROW, OUTPUT_ROW, #1
1139 ldr RGB, [INPUT_BUF], #4
1140
1141 /* Inner loop over pixels */
1142 subs N, N, #8
1143 blt 3f
1144 do_load \bpp, 8
1145 do_rgb_to_yuv_stage1
1146 subs N, N, #8
1147 blt 2f
11481:
1149 do_rgb_to_yuv_stage2_store_load_stage1
1150 subs N, N, #8
1151 bge 1b
11522:
1153 do_rgb_to_yuv_stage2
1154 do_store 8
1155 tst N, #7
1156 beq 8f
11573:
1158 tst N, #4
1159 beq 3f
1160 do_load \bpp, 4
11613:
1162 tst N, #2
1163 beq 4f
1164 do_load \bpp, 2
11654:
1166 tst N, #1
1167 beq 5f
1168 do_load \bpp, 1
11695:
1170 do_rgb_to_yuv
1171 tst N, #4
1172 beq 6f
1173 do_store 4
11746:
1175 tst N, #2
1176 beq 7f
1177 do_store 2
11787:
1179 tst N, #1
1180 beq 8f
1181 do_store 1
11828:
1183 subs NUM_ROWS, NUM_ROWS, #1
1184 bgt 0b
11859:
1186 /* Restore all registers and return */
1187 vpop {d8-d15}
1188 pop {r4, r5, r6, r7, r8, r9, r10, pc}
1189
1190 .unreq OUTPUT_WIDTH
1191 .unreq OUTPUT_ROW
1192 .unreq INPUT_BUF
1193 .unreq NUM_ROWS
1194 .unreq OUTPUT_BUF0
1195 .unreq OUTPUT_BUF1
1196 .unreq OUTPUT_BUF2
1197 .unreq RGB
1198 .unreq Y
1199 .unreq U
1200 .unreq V
1201 .unreq N
1202.endfunc
1203
1204.purgem do_rgb_to_yuv
1205.purgem do_rgb_to_yuv_stage1
1206.purgem do_rgb_to_yuv_stage2
1207.purgem do_rgb_to_yuv_stage2_store_load_stage1
1208
1209.endm
1210
1211/*--------------------------------- id ----- bpp R G B */
1212generate_jsimd_rgb_ycc_convert_neon extrgb, 24, 0, 1, 2
1213generate_jsimd_rgb_ycc_convert_neon extbgr, 24, 2, 1, 0
1214generate_jsimd_rgb_ycc_convert_neon extrgbx, 32, 0, 1, 2
1215generate_jsimd_rgb_ycc_convert_neon extbgrx, 32, 2, 1, 0
1216generate_jsimd_rgb_ycc_convert_neon extxbgr, 32, 3, 2, 1
1217generate_jsimd_rgb_ycc_convert_neon extxrgb, 32, 1, 2, 3
1218
1219.purgem do_load
1220.purgem do_store
1221
1222/*****************************************************************************/
1223
1224/*
DRCb7400542011-08-10 23:31:13 +00001225 * Load data into workspace, applying unsigned->signed conversion
1226 *
1227 * TODO: can be combined with 'jsimd_fdct_ifast_neon' to get
1228 * rid of VST1.16 instructions
1229 */
1230
1231asm_function jsimd_convsamp_neon
1232 SAMPLE_DATA .req r0
1233 START_COL .req r1
1234 WORKSPACE .req r2
1235 TMP1 .req r3
1236 TMP2 .req r4
1237 TMP3 .req r5
1238 TMP4 .req ip
1239
1240 push {r4, r5}
1241 vmov.u8 d0, #128
1242
1243 ldmia SAMPLE_DATA!, {TMP1, TMP2, TMP3, TMP4}
1244 add TMP1, TMP1, START_COL
1245 add TMP2, TMP2, START_COL
1246 add TMP3, TMP3, START_COL
1247 add TMP4, TMP4, START_COL
1248 vld1.8 {d16}, [TMP1]
1249 vsubl.u8 q8, d16, d0
1250 vld1.8 {d18}, [TMP2]
1251 vsubl.u8 q9, d18, d0
1252 vld1.8 {d20}, [TMP3]
1253 vsubl.u8 q10, d20, d0
1254 vld1.8 {d22}, [TMP4]
1255 ldmia SAMPLE_DATA!, {TMP1, TMP2, TMP3, TMP4}
1256 vsubl.u8 q11, d22, d0
1257 vst1.16 {d16, d17, d18, d19}, [WORKSPACE, :128]!
1258 add TMP1, TMP1, START_COL
1259 add TMP2, TMP2, START_COL
1260 vst1.16 {d20, d21, d22, d23}, [WORKSPACE, :128]!
1261 add TMP3, TMP3, START_COL
1262 add TMP4, TMP4, START_COL
1263 vld1.8 {d24}, [TMP1]
1264 vsubl.u8 q12, d24, d0
1265 vld1.8 {d26}, [TMP2]
1266 vsubl.u8 q13, d26, d0
1267 vld1.8 {d28}, [TMP3]
1268 vsubl.u8 q14, d28, d0
1269 vld1.8 {d30}, [TMP4]
1270 vsubl.u8 q15, d30, d0
1271 vst1.16 {d24, d25, d26, d27}, [WORKSPACE, :128]!
1272 vst1.16 {d28, d29, d30, d31}, [WORKSPACE, :128]!
1273 pop {r4, r5}
1274 bx lr
1275
1276 .unreq SAMPLE_DATA
1277 .unreq START_COL
1278 .unreq WORKSPACE
1279 .unreq TMP1
1280 .unreq TMP2
1281 .unreq TMP3
1282 .unreq TMP4
1283.endfunc
1284
1285/*****************************************************************************/
1286
1287/*
1288 * jsimd_fdct_ifast_neon
1289 *
1290 * This function contains a fast, not so accurate integer implementation of
1291 * the forward DCT (Discrete Cosine Transform). It uses the same calculations
1292 * and produces exactly the same output as IJG's original 'jpeg_fdct_ifast'
1293 * function from jfdctfst.c
1294 *
1295 * TODO: can be combined with 'jsimd_convsamp_neon' to get
1296 * rid of a bunch of VLD1.16 instructions
1297 */
1298
1299#define XFIX_0_382683433 d0[0]
1300#define XFIX_0_541196100 d0[1]
1301#define XFIX_0_707106781 d0[2]
1302#define XFIX_1_306562965 d0[3]
1303
1304.balign 16
1305jsimd_fdct_ifast_neon_consts:
1306 .short (98 * 128) /* XFIX_0_382683433 */
1307 .short (139 * 128) /* XFIX_0_541196100 */
1308 .short (181 * 128) /* XFIX_0_707106781 */
1309 .short (334 * 128 - 256 * 128) /* XFIX_1_306562965 */
1310
1311asm_function jsimd_fdct_ifast_neon
1312
1313 DATA .req r0
1314 TMP .req ip
1315
1316 vpush {d8-d15}
1317
1318 /* Load constants */
1319 adr TMP, jsimd_fdct_ifast_neon_consts
1320 vld1.16 {d0}, [TMP, :64]
1321
1322 /* Load all DATA into NEON registers with the following allocation:
1323 * 0 1 2 3 | 4 5 6 7
1324 * ---------+--------
1325 * 0 | d16 | d17 | q8
1326 * 1 | d18 | d19 | q9
1327 * 2 | d20 | d21 | q10
1328 * 3 | d22 | d23 | q11
1329 * 4 | d24 | d25 | q12
1330 * 5 | d26 | d27 | q13
1331 * 6 | d28 | d29 | q14
1332 * 7 | d30 | d31 | q15
1333 */
1334
1335 vld1.16 {d16, d17, d18, d19}, [DATA, :128]!
1336 vld1.16 {d20, d21, d22, d23}, [DATA, :128]!
1337 vld1.16 {d24, d25, d26, d27}, [DATA, :128]!
1338 vld1.16 {d28, d29, d30, d31}, [DATA, :128]
1339 sub DATA, DATA, #(128 - 32)
1340
1341 mov TMP, #2
13421:
1343 /* Transpose */
1344 vtrn.16 q12, q13
1345 vtrn.16 q10, q11
1346 vtrn.16 q8, q9
1347 vtrn.16 q14, q15
1348 vtrn.32 q9, q11
1349 vtrn.32 q13, q15
1350 vtrn.32 q8, q10
1351 vtrn.32 q12, q14
1352 vswp d30, d23
1353 vswp d24, d17
1354 vswp d26, d19
1355 /* 1-D FDCT */
1356 vadd.s16 q2, q11, q12
1357 vswp d28, d21
1358 vsub.s16 q12, q11, q12
1359 vsub.s16 q6, q10, q13
1360 vadd.s16 q10, q10, q13
1361 vsub.s16 q7, q9, q14
1362 vadd.s16 q9, q9, q14
1363 vsub.s16 q1, q8, q15
1364 vadd.s16 q8, q8, q15
1365 vsub.s16 q4, q9, q10
1366 vsub.s16 q5, q8, q2
1367 vadd.s16 q3, q9, q10
1368 vadd.s16 q4, q4, q5
1369 vadd.s16 q2, q8, q2
1370 vqdmulh.s16 q4, q4, XFIX_0_707106781
1371 vadd.s16 q11, q12, q6
1372 vadd.s16 q8, q2, q3
1373 vsub.s16 q12, q2, q3
1374 vadd.s16 q3, q6, q7
1375 vadd.s16 q7, q7, q1
1376 vqdmulh.s16 q3, q3, XFIX_0_707106781
1377 vsub.s16 q6, q11, q7
1378 vadd.s16 q10, q5, q4
1379 vqdmulh.s16 q6, q6, XFIX_0_382683433
1380 vsub.s16 q14, q5, q4
1381 vqdmulh.s16 q11, q11, XFIX_0_541196100
1382 vqdmulh.s16 q5, q7, XFIX_1_306562965
1383 vadd.s16 q4, q1, q3
1384 vsub.s16 q3, q1, q3
1385 vadd.s16 q7, q7, q6
1386 vadd.s16 q11, q11, q6
1387 vadd.s16 q7, q7, q5
1388 vadd.s16 q13, q3, q11
1389 vsub.s16 q11, q3, q11
1390 vadd.s16 q9, q4, q7
1391 vsub.s16 q15, q4, q7
1392 subs TMP, TMP, #1
1393 bne 1b
1394
1395 /* store results */
1396 vst1.16 {d16, d17, d18, d19}, [DATA, :128]!
1397 vst1.16 {d20, d21, d22, d23}, [DATA, :128]!
1398 vst1.16 {d24, d25, d26, d27}, [DATA, :128]!
1399 vst1.16 {d28, d29, d30, d31}, [DATA, :128]
1400
1401 vpop {d8-d15}
1402 bx lr
1403
1404 .unreq DATA
1405 .unreq TMP
1406.endfunc
1407
1408/*****************************************************************************/