|
|
1.1 root 1: /*
2: * This file is part of the Scale2x project.
3: *
4: * Copyright (C) 2001-2003 Andrea Mazzoleni
5: *
6: * This program is free software; you can redistribute it and/or modify
7: * it under the terms of the GNU General Public License as published by
8: * the Free Software Foundation; either version 2 of the License, or
9: * (at your option) any later version.
10: *
11: * This program is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: * GNU General Public License for more details.
15: *
16: * You should have received a copy of the GNU General Public License
17: * along with this program; if not, write to the Free Software
18: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19: */
20:
21: /*
22: * This file contains a fast C and MMX implementation of the Scale2x effect.
23: *
24: * You can find an high level description of the effect at :
25: *
26: * http://scale2x.sourceforge.net/
27: *
28: * Alternatively at the previous license terms, you are allowed to use this
29: * code in your program with these conditions:
30: * - the program is not used in commercial activities.
31: * - the whole source code of the program is released with the binary.
32: * - derivative works of the program are allowed.
33: */
34:
35: #ifndef __SCALE2X_H
36: #define __SCALE2X_H
37:
38: #include <assert.h>
39:
40: /***************************************************************************/
41: /* Basic types */
42:
43: typedef unsigned char scale2x_uint8;
44: typedef unsigned short scale2x_uint16;
45: typedef unsigned scale2x_uint32;
46:
47: /***************************************************************************/
48: /* Scale2x C implementation */
49:
50: static void scale2x_8_def_single(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
51: {
52: assert(count >= 2);
53:
54: /* first pixel */
55: dst[0] = src1[0];
56: if (src1[1] == src0[0] && src2[0] != src0[0])
57: dst[1] = src0[0];
58: else
59: dst[1] = src1[0];
60: ++src0;
61: ++src1;
62: ++src2;
63: dst += 2;
64:
65: /* central pixels */
66: count -= 2;
67: while (count) {
68: if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
69: dst[0] = src0[0];
70: else
71: dst[0] = src1[0];
72: if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
73: dst[1] = src0[0];
74: else
75: dst[1] = src1[0];
76:
77: ++src0;
78: ++src1;
79: ++src2;
80: dst += 2;
81: --count;
82: }
83:
84: /* last pixel */
85: if (src1[-1] == src0[0] && src2[0] != src0[0])
86: dst[0] = src0[0];
87: else
88: dst[0] = src1[0];
89: dst[1] = src1[0];
90: }
91:
92: static void scale2x_16_def_single(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
93: {
94: assert(count >= 2);
95:
96: /* first pixel */
97: dst[0] = src1[0];
98: if (src1[1] == src0[0] && src2[0] != src0[0])
99: dst[1] = src0[0];
100: else
101: dst[1] = src1[0];
102: ++src0;
103: ++src1;
104: ++src2;
105: dst += 2;
106:
107: /* central pixels */
108: count -= 2;
109: while (count) {
110: if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
111: dst[0] = src0[0];
112: else
113: dst[0] = src1[0];
114: if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
115: dst[1] = src0[0];
116: else
117: dst[1] = src1[0];
118:
119: ++src0;
120: ++src1;
121: ++src2;
122: dst += 2;
123: --count;
124: }
125:
126: /* last pixel */
127: if (src1[-1] == src0[0] && src2[0] != src0[0])
128: dst[0] = src0[0];
129: else
130: dst[0] = src1[0];
131: dst[1] = src1[0];
132: }
133:
134: static void scale2x_32_def_single(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
135: {
136: assert(count >= 2);
137:
138: /* first pixel */
139: dst[0] = src1[0];
140: if (src1[1] == src0[0] && src2[0] != src0[0])
141: dst[1] = src0[0];
142: else
143: dst[1] = src1[0];
144: ++src0;
145: ++src1;
146: ++src2;
147: dst += 2;
148:
149: /* central pixels */
150: count -= 2;
151: while (count) {
152: if (src1[-1] == src0[0] && src2[0] != src0[0] && src1[1] != src0[0])
153: dst[0] = src0[0];
154: else
155: dst[0] = src1[0];
156: if (src1[1] == src0[0] && src2[0] != src0[0] && src1[-1] != src0[0])
157: dst[1] = src0[0];
158: else
159: dst[1] = src1[0];
160:
161: ++src0;
162: ++src1;
163: ++src2;
164: dst += 2;
165: --count;
166: }
167:
168: /* last pixel */
169: if (src1[-1] == src0[0] && src2[0] != src0[0])
170: dst[0] = src0[0];
171: else
172: dst[0] = src1[0];
173: dst[1] = src1[0];
174: }
175:
176: /**
177: * Scale by a factor of 2 a row of pixels of 8 bits.
178: * The function is implemented in C.
179: * The pixels over the left and right borders are assumed of the same color of
180: * the pixels on the border.
181: * \param src0 Pointer at the first pixel of the previous row.
182: * \param src1 Pointer at the first pixel of the current row.
183: * \param src2 Pointer at the first pixel of the next row.
184: * \param count Length in pixels of the src0, src1 and src2 rows.
185: * It must be at least 2.
186: * \param dst0 First destination row, double length in pixels.
187: * \param dst1 Second destination row, double length in pixels.
188: */
189: static inline void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
190: {
191: assert(count >= 2);
192:
193: scale2x_8_def_single(dst0, src0, src1, src2, count);
194: scale2x_8_def_single(dst1, src2, src1, src0, count);
195: }
196:
197: /**
198: * Scale by a factor of 2 a row of pixels of 16 bits.
199: * This function operates like scale2x_8_def() but for 16 bits pixels.
200: * \param src0 Pointer at the first pixel of the previous row.
201: * \param src1 Pointer at the first pixel of the current row.
202: * \param src2 Pointer at the first pixel of the next row.
203: * \param count Length in pixels of the src0, src1 and src2 rows.
204: * It must be at least 2.
205: * \param dst0 First destination row, double length in pixels.
206: * \param dst1 Second destination row, double length in pixels.
207: */
208: static inline void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
209: {
210: assert(count >= 2);
211:
212: scale2x_16_def_single(dst0, src0, src1, src2, count);
213: scale2x_16_def_single(dst1, src2, src1, src0, count);
214: }
215:
216: /**
217: * Scale by a factor of 2 a row of pixels of 32 bits.
218: * This function operates like scale2x_8_def() but for 32 bits pixels.
219: * \param src0 Pointer at the first pixel of the previous row.
220: * \param src1 Pointer at the first pixel of the current row.
221: * \param src2 Pointer at the first pixel of the next row.
222: * \param count Length in pixels of the src0, src1 and src2 rows.
223: * It must be at least 2.
224: * \param dst0 First destination row, double length in pixels.
225: * \param dst1 Second destination row, double length in pixels.
226: */
227: static inline void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
228: {
229: assert(count >= 2);
230:
231: scale2x_32_def_single(dst0, src0, src1, src2, count);
232: scale2x_32_def_single(dst1, src2, src1, src0, count);
233: }
234:
235: /***************************************************************************/
236: /* Scale2x MMX implementation */
237:
238: #if defined(__GNUC__) && defined(__i386__)
239:
240: /*
241: * Apply the Scale2x effect at a single row.
242: * This function must be called only by the other scale2x functions.
243: *
244: * Considering the pixel map :
245: *
246: * ABC (src0)
247: * DEF (src1)
248: * GHI (src2)
249: *
250: * this functions compute 2 new pixels in substitution of the source pixel E
251: * like this map :
252: *
253: * ab (dst)
254: *
255: * with these variables :
256: *
257: * ¤t -> E
258: * ¤t_left -> D
259: * ¤t_right -> F
260: * ¤t_upper -> B
261: * ¤t_lower -> H
262: *
263: * %0 -> current_upper
264: * %1 -> current
265: * %2 -> current_lower
266: * %3 -> dst
267: * %4 -> counter
268: *
269: * %mm0 -> *current_left
270: * %mm1 -> *current_next
271: * %mm2 -> tmp0
272: * %mm3 -> tmp1
273: * %mm4 -> tmp2
274: * %mm5 -> tmp3
275: * %mm6 -> *current_upper
276: * %mm7 -> *current
277: */
278: static inline void scale2x_8_mmx_single(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
279: {
280: assert(count >= 16);
281: assert(count % 8 == 0);
282:
283: /* always do the first and last run */
284: count -= 2*8;
285:
286: __asm__ __volatile__(
287: /* first run */
288: /* set the current, current_pre, current_next registers */
289: "movq 0(%1), %%mm0\n"
290: "movq 0(%1), %%mm7\n"
291: "movq 8(%1), %%mm1\n"
292: "psllq $56, %%mm0\n"
293: "psllq $56, %%mm1\n"
294: "psrlq $56, %%mm0\n"
295: "movq %%mm7, %%mm2\n"
296: "movq %%mm7, %%mm3\n"
297: "psllq $8, %%mm2\n"
298: "psrlq $8, %%mm3\n"
299: "por %%mm2, %%mm0\n"
300: "por %%mm3, %%mm1\n"
301:
302: /* current_upper */
303: "movq (%0), %%mm6\n"
304:
305: /* compute the upper-left pixel for dst on %%mm2 */
306: /* compute the upper-right pixel for dst on %%mm4 */
307: "movq %%mm0, %%mm2\n"
308: "movq %%mm1, %%mm4\n"
309: "movq %%mm0, %%mm3\n"
310: "movq %%mm1, %%mm5\n"
311: "pcmpeqb %%mm6, %%mm2\n"
312: "pcmpeqb %%mm6, %%mm4\n"
313: "pcmpeqb (%2), %%mm3\n"
314: "pcmpeqb (%2), %%mm5\n"
315: "pandn %%mm2, %%mm3\n"
316: "pandn %%mm4, %%mm5\n"
317: "movq %%mm0, %%mm2\n"
318: "movq %%mm1, %%mm4\n"
319: "pcmpeqb %%mm1, %%mm2\n"
320: "pcmpeqb %%mm0, %%mm4\n"
321: "pandn %%mm3, %%mm2\n"
322: "pandn %%mm5, %%mm4\n"
323: "movq %%mm2, %%mm3\n"
324: "movq %%mm4, %%mm5\n"
325: "pand %%mm6, %%mm2\n"
326: "pand %%mm6, %%mm4\n"
327: "pandn %%mm7, %%mm3\n"
328: "pandn %%mm7, %%mm5\n"
329: "por %%mm3, %%mm2\n"
330: "por %%mm5, %%mm4\n"
331:
332: /* set *dst */
333: "movq %%mm2, %%mm3\n"
334: "punpcklbw %%mm4, %%mm2\n"
335: "punpckhbw %%mm4, %%mm3\n"
336: "movq %%mm2, (%3)\n"
337: "movq %%mm3, 8(%3)\n"
338:
339: /* next */
340: "addl $8, %0\n"
341: "addl $8, %1\n"
342: "addl $8, %2\n"
343: "addl $16, %3\n"
344:
345: /* central runs */
346: "shrl $3, %4\n"
347: "jz 1f\n"
348:
349: "0:\n"
350:
351: /* set the current, current_pre, current_next registers */
352: "movq -8(%1), %%mm0\n"
353: "movq (%1), %%mm7\n"
354: "movq 8(%1), %%mm1\n"
355: "psrlq $56, %%mm0\n"
356: "psllq $56, %%mm1\n"
357: "movq %%mm7, %%mm2\n"
358: "movq %%mm7, %%mm3\n"
359: "psllq $8, %%mm2\n"
360: "psrlq $8, %%mm3\n"
361: "por %%mm2, %%mm0\n"
362: "por %%mm3, %%mm1\n"
363:
364: /* current_upper */
365: "movq (%0), %%mm6\n"
366:
367: /* compute the upper-left pixel for dst on %%mm2 */
368: /* compute the upper-right pixel for dst on %%mm4 */
369: "movq %%mm0, %%mm2\n"
370: "movq %%mm1, %%mm4\n"
371: "movq %%mm0, %%mm3\n"
372: "movq %%mm1, %%mm5\n"
373: "pcmpeqb %%mm6, %%mm2\n"
374: "pcmpeqb %%mm6, %%mm4\n"
375: "pcmpeqb (%2), %%mm3\n"
376: "pcmpeqb (%2), %%mm5\n"
377: "pandn %%mm2, %%mm3\n"
378: "pandn %%mm4, %%mm5\n"
379: "movq %%mm0, %%mm2\n"
380: "movq %%mm1, %%mm4\n"
381: "pcmpeqb %%mm1, %%mm2\n"
382: "pcmpeqb %%mm0, %%mm4\n"
383: "pandn %%mm3, %%mm2\n"
384: "pandn %%mm5, %%mm4\n"
385: "movq %%mm2, %%mm3\n"
386: "movq %%mm4, %%mm5\n"
387: "pand %%mm6, %%mm2\n"
388: "pand %%mm6, %%mm4\n"
389: "pandn %%mm7, %%mm3\n"
390: "pandn %%mm7, %%mm5\n"
391: "por %%mm3, %%mm2\n"
392: "por %%mm5, %%mm4\n"
393:
394: /* set *dst */
395: "movq %%mm2, %%mm3\n"
396: "punpcklbw %%mm4, %%mm2\n"
397: "punpckhbw %%mm4, %%mm3\n"
398: "movq %%mm2, (%3)\n"
399: "movq %%mm3, 8(%3)\n"
400:
401: /* next */
402: "addl $8, %0\n"
403: "addl $8, %1\n"
404: "addl $8, %2\n"
405: "addl $16, %3\n"
406:
407: "decl %4\n"
408: "jnz 0b\n"
409: "1:\n"
410:
411: /* final run */
412: /* set the current, current_pre, current_next registers */
413: "movq (%1), %%mm1\n"
414: "movq (%1), %%mm7\n"
415: "movq -8(%1), %%mm0\n"
416: "psrlq $56, %%mm1\n"
417: "psrlq $56, %%mm0\n"
418: "psllq $56, %%mm1\n"
419: "movq %%mm7, %%mm2\n"
420: "movq %%mm7, %%mm3\n"
421: "psllq $8, %%mm2\n"
422: "psrlq $8, %%mm3\n"
423: "por %%mm2, %%mm0\n"
424: "por %%mm3, %%mm1\n"
425:
426: /* current_upper */
427: "movq (%0), %%mm6\n"
428:
429: /* compute the upper-left pixel for dst on %%mm2 */
430: /* compute the upper-right pixel for dst on %%mm4 */
431: "movq %%mm0, %%mm2\n"
432: "movq %%mm1, %%mm4\n"
433: "movq %%mm0, %%mm3\n"
434: "movq %%mm1, %%mm5\n"
435: "pcmpeqb %%mm6, %%mm2\n"
436: "pcmpeqb %%mm6, %%mm4\n"
437: "pcmpeqb (%2), %%mm3\n"
438: "pcmpeqb (%2), %%mm5\n"
439: "pandn %%mm2, %%mm3\n"
440: "pandn %%mm4, %%mm5\n"
441: "movq %%mm0, %%mm2\n"
442: "movq %%mm1, %%mm4\n"
443: "pcmpeqb %%mm1, %%mm2\n"
444: "pcmpeqb %%mm0, %%mm4\n"
445: "pandn %%mm3, %%mm2\n"
446: "pandn %%mm5, %%mm4\n"
447: "movq %%mm2, %%mm3\n"
448: "movq %%mm4, %%mm5\n"
449: "pand %%mm6, %%mm2\n"
450: "pand %%mm6, %%mm4\n"
451: "pandn %%mm7, %%mm3\n"
452: "pandn %%mm7, %%mm5\n"
453: "por %%mm3, %%mm2\n"
454: "por %%mm5, %%mm4\n"
455:
456: /* set *dst */
457: "movq %%mm2, %%mm3\n"
458: "punpcklbw %%mm4, %%mm2\n"
459: "punpckhbw %%mm4, %%mm3\n"
460: "movq %%mm2, (%3)\n"
461: "movq %%mm3, 8(%3)\n"
462:
463: : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
464: :
465: : "cc"
466: );
467: }
468:
469: static inline void scale2x_16_mmx_single(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
470: {
471: assert(count >= 8);
472: assert(count % 4 == 0);
473:
474: /* always do the first and last run */
475: count -= 2*4;
476:
477: __asm__ __volatile__(
478: /* first run */
479: /* set the current, current_pre, current_next registers */
480: "movq 0(%1), %%mm0\n"
481: "movq 0(%1), %%mm7\n"
482: "movq 8(%1), %%mm1\n"
483: "psllq $48, %%mm0\n"
484: "psllq $48, %%mm1\n"
485: "psrlq $48, %%mm0\n"
486: "movq %%mm7, %%mm2\n"
487: "movq %%mm7, %%mm3\n"
488: "psllq $16, %%mm2\n"
489: "psrlq $16, %%mm3\n"
490: "por %%mm2, %%mm0\n"
491: "por %%mm3, %%mm1\n"
492:
493: /* current_upper */
494: "movq (%0), %%mm6\n"
495:
496: /* compute the upper-left pixel for dst on %%mm2 */
497: /* compute the upper-right pixel for dst on %%mm4 */
498: "movq %%mm0, %%mm2\n"
499: "movq %%mm1, %%mm4\n"
500: "movq %%mm0, %%mm3\n"
501: "movq %%mm1, %%mm5\n"
502: "pcmpeqw %%mm6, %%mm2\n"
503: "pcmpeqw %%mm6, %%mm4\n"
504: "pcmpeqw (%2), %%mm3\n"
505: "pcmpeqw (%2), %%mm5\n"
506: "pandn %%mm2, %%mm3\n"
507: "pandn %%mm4, %%mm5\n"
508: "movq %%mm0, %%mm2\n"
509: "movq %%mm1, %%mm4\n"
510: "pcmpeqw %%mm1, %%mm2\n"
511: "pcmpeqw %%mm0, %%mm4\n"
512: "pandn %%mm3, %%mm2\n"
513: "pandn %%mm5, %%mm4\n"
514: "movq %%mm2, %%mm3\n"
515: "movq %%mm4, %%mm5\n"
516: "pand %%mm6, %%mm2\n"
517: "pand %%mm6, %%mm4\n"
518: "pandn %%mm7, %%mm3\n"
519: "pandn %%mm7, %%mm5\n"
520: "por %%mm3, %%mm2\n"
521: "por %%mm5, %%mm4\n"
522:
523: /* set *dst */
524: "movq %%mm2, %%mm3\n"
525: "punpcklwd %%mm4, %%mm2\n"
526: "punpckhwd %%mm4, %%mm3\n"
527: "movq %%mm2, (%3)\n"
528: "movq %%mm3, 8(%3)\n"
529:
530: /* next */
531: "addl $8, %0\n"
532: "addl $8, %1\n"
533: "addl $8, %2\n"
534: "addl $16, %3\n"
535:
536: /* central runs */
537: "shrl $2, %4\n"
538: "jz 1f\n"
539:
540: "0:\n"
541:
542: /* set the current, current_pre, current_next registers */
543: "movq -8(%1), %%mm0\n"
544: "movq (%1), %%mm7\n"
545: "movq 8(%1), %%mm1\n"
546: "psrlq $48, %%mm0\n"
547: "psllq $48, %%mm1\n"
548: "movq %%mm7, %%mm2\n"
549: "movq %%mm7, %%mm3\n"
550: "psllq $16, %%mm2\n"
551: "psrlq $16, %%mm3\n"
552: "por %%mm2, %%mm0\n"
553: "por %%mm3, %%mm1\n"
554:
555: /* current_upper */
556: "movq (%0), %%mm6\n"
557:
558: /* compute the upper-left pixel for dst on %%mm2 */
559: /* compute the upper-right pixel for dst on %%mm4 */
560: "movq %%mm0, %%mm2\n"
561: "movq %%mm1, %%mm4\n"
562: "movq %%mm0, %%mm3\n"
563: "movq %%mm1, %%mm5\n"
564: "pcmpeqw %%mm6, %%mm2\n"
565: "pcmpeqw %%mm6, %%mm4\n"
566: "pcmpeqw (%2), %%mm3\n"
567: "pcmpeqw (%2), %%mm5\n"
568: "pandn %%mm2, %%mm3\n"
569: "pandn %%mm4, %%mm5\n"
570: "movq %%mm0, %%mm2\n"
571: "movq %%mm1, %%mm4\n"
572: "pcmpeqw %%mm1, %%mm2\n"
573: "pcmpeqw %%mm0, %%mm4\n"
574: "pandn %%mm3, %%mm2\n"
575: "pandn %%mm5, %%mm4\n"
576: "movq %%mm2, %%mm3\n"
577: "movq %%mm4, %%mm5\n"
578: "pand %%mm6, %%mm2\n"
579: "pand %%mm6, %%mm4\n"
580: "pandn %%mm7, %%mm3\n"
581: "pandn %%mm7, %%mm5\n"
582: "por %%mm3, %%mm2\n"
583: "por %%mm5, %%mm4\n"
584:
585: /* set *dst */
586: "movq %%mm2, %%mm3\n"
587: "punpcklwd %%mm4, %%mm2\n"
588: "punpckhwd %%mm4, %%mm3\n"
589: "movq %%mm2, (%3)\n"
590: "movq %%mm3, 8(%3)\n"
591:
592: /* next */
593: "addl $8, %0\n"
594: "addl $8, %1\n"
595: "addl $8, %2\n"
596: "addl $16, %3\n"
597:
598: "decl %4\n"
599: "jnz 0b\n"
600: "1:\n"
601:
602: /* final run */
603: /* set the current, current_pre, current_next registers */
604: "movq (%1), %%mm1\n"
605: "movq (%1), %%mm7\n"
606: "movq -8(%1), %%mm0\n"
607: "psrlq $48, %%mm1\n"
608: "psrlq $48, %%mm0\n"
609: "psllq $48, %%mm1\n"
610: "movq %%mm7, %%mm2\n"
611: "movq %%mm7, %%mm3\n"
612: "psllq $16, %%mm2\n"
613: "psrlq $16, %%mm3\n"
614: "por %%mm2, %%mm0\n"
615: "por %%mm3, %%mm1\n"
616:
617: /* current_upper */
618: "movq (%0), %%mm6\n"
619:
620: /* compute the upper-left pixel for dst on %%mm2 */
621: /* compute the upper-right pixel for dst on %%mm4 */
622: "movq %%mm0, %%mm2\n"
623: "movq %%mm1, %%mm4\n"
624: "movq %%mm0, %%mm3\n"
625: "movq %%mm1, %%mm5\n"
626: "pcmpeqw %%mm6, %%mm2\n"
627: "pcmpeqw %%mm6, %%mm4\n"
628: "pcmpeqw (%2), %%mm3\n"
629: "pcmpeqw (%2), %%mm5\n"
630: "pandn %%mm2, %%mm3\n"
631: "pandn %%mm4, %%mm5\n"
632: "movq %%mm0, %%mm2\n"
633: "movq %%mm1, %%mm4\n"
634: "pcmpeqw %%mm1, %%mm2\n"
635: "pcmpeqw %%mm0, %%mm4\n"
636: "pandn %%mm3, %%mm2\n"
637: "pandn %%mm5, %%mm4\n"
638: "movq %%mm2, %%mm3\n"
639: "movq %%mm4, %%mm5\n"
640: "pand %%mm6, %%mm2\n"
641: "pand %%mm6, %%mm4\n"
642: "pandn %%mm7, %%mm3\n"
643: "pandn %%mm7, %%mm5\n"
644: "por %%mm3, %%mm2\n"
645: "por %%mm5, %%mm4\n"
646:
647: /* set *dst */
648: "movq %%mm2, %%mm3\n"
649: "punpcklwd %%mm4, %%mm2\n"
650: "punpckhwd %%mm4, %%mm3\n"
651: "movq %%mm2, (%3)\n"
652: "movq %%mm3, 8(%3)\n"
653:
654: : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
655: :
656: : "cc"
657: );
658: }
659:
660: static inline void scale2x_32_mmx_single(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
661: {
662: assert(count >= 4);
663: assert(count % 2 == 0);
664:
665: /* always do the first and last run */
666: count -= 2*2;
667:
668: __asm__ __volatile__(
669: /* first run */
670: /* set the current, current_pre, current_next registers */
671: "movq 0(%1), %%mm0\n"
672: "movq 0(%1), %%mm7\n"
673: "movq 8(%1), %%mm1\n"
674: "psllq $32, %%mm0\n"
675: "psllq $32, %%mm1\n"
676: "psrlq $32, %%mm0\n"
677: "movq %%mm7, %%mm2\n"
678: "movq %%mm7, %%mm3\n"
679: "psllq $32, %%mm2\n"
680: "psrlq $32, %%mm3\n"
681: "por %%mm2, %%mm0\n"
682: "por %%mm3, %%mm1\n"
683:
684: /* current_upper */
685: "movq (%0), %%mm6\n"
686:
687: /* compute the upper-left pixel for dst on %%mm2 */
688: /* compute the upper-right pixel for dst on %%mm4 */
689: "movq %%mm0, %%mm2\n"
690: "movq %%mm1, %%mm4\n"
691: "movq %%mm0, %%mm3\n"
692: "movq %%mm1, %%mm5\n"
693: "pcmpeqd %%mm6, %%mm2\n"
694: "pcmpeqd %%mm6, %%mm4\n"
695: "pcmpeqd (%2), %%mm3\n"
696: "pcmpeqd (%2), %%mm5\n"
697: "pandn %%mm2, %%mm3\n"
698: "pandn %%mm4, %%mm5\n"
699: "movq %%mm0, %%mm2\n"
700: "movq %%mm1, %%mm4\n"
701: "pcmpeqd %%mm1, %%mm2\n"
702: "pcmpeqd %%mm0, %%mm4\n"
703: "pandn %%mm3, %%mm2\n"
704: "pandn %%mm5, %%mm4\n"
705: "movq %%mm2, %%mm3\n"
706: "movq %%mm4, %%mm5\n"
707: "pand %%mm6, %%mm2\n"
708: "pand %%mm6, %%mm4\n"
709: "pandn %%mm7, %%mm3\n"
710: "pandn %%mm7, %%mm5\n"
711: "por %%mm3, %%mm2\n"
712: "por %%mm5, %%mm4\n"
713:
714: /* set *dst */
715: "movq %%mm2, %%mm3\n"
716: "punpckldq %%mm4, %%mm2\n"
717: "punpckhdq %%mm4, %%mm3\n"
718: "movq %%mm2, (%3)\n"
719: "movq %%mm3, 8(%3)\n"
720:
721: /* next */
722: "addl $8, %0\n"
723: "addl $8, %1\n"
724: "addl $8, %2\n"
725: "addl $16, %3\n"
726:
727: /* central runs */
728: "shrl $1, %4\n"
729: "jz 1f\n"
730:
731: "0:\n"
732:
733: /* set the current, current_pre, current_next registers */
734: "movq -8(%1), %%mm0\n"
735: "movq (%1), %%mm7\n"
736: "movq 8(%1), %%mm1\n"
737: "psrlq $32, %%mm0\n"
738: "psllq $32, %%mm1\n"
739: "movq %%mm7, %%mm2\n"
740: "movq %%mm7, %%mm3\n"
741: "psllq $32, %%mm2\n"
742: "psrlq $32, %%mm3\n"
743: "por %%mm2, %%mm0\n"
744: "por %%mm3, %%mm1\n"
745:
746: /* current_upper */
747: "movq (%0), %%mm6\n"
748:
749: /* compute the upper-left pixel for dst on %%mm2 */
750: /* compute the upper-right pixel for dst on %%mm4 */
751: "movq %%mm0, %%mm2\n"
752: "movq %%mm1, %%mm4\n"
753: "movq %%mm0, %%mm3\n"
754: "movq %%mm1, %%mm5\n"
755: "pcmpeqd %%mm6, %%mm2\n"
756: "pcmpeqd %%mm6, %%mm4\n"
757: "pcmpeqd (%2), %%mm3\n"
758: "pcmpeqd (%2), %%mm5\n"
759: "pandn %%mm2, %%mm3\n"
760: "pandn %%mm4, %%mm5\n"
761: "movq %%mm0, %%mm2\n"
762: "movq %%mm1, %%mm4\n"
763: "pcmpeqd %%mm1, %%mm2\n"
764: "pcmpeqd %%mm0, %%mm4\n"
765: "pandn %%mm3, %%mm2\n"
766: "pandn %%mm5, %%mm4\n"
767: "movq %%mm2, %%mm3\n"
768: "movq %%mm4, %%mm5\n"
769: "pand %%mm6, %%mm2\n"
770: "pand %%mm6, %%mm4\n"
771: "pandn %%mm7, %%mm3\n"
772: "pandn %%mm7, %%mm5\n"
773: "por %%mm3, %%mm2\n"
774: "por %%mm5, %%mm4\n"
775:
776: /* set *dst */
777: "movq %%mm2, %%mm3\n"
778: "punpckldq %%mm4, %%mm2\n"
779: "punpckhdq %%mm4, %%mm3\n"
780: "movq %%mm2, (%3)\n"
781: "movq %%mm3, 8(%3)\n"
782:
783: /* next */
784: "addl $8, %0\n"
785: "addl $8, %1\n"
786: "addl $8, %2\n"
787: "addl $16, %3\n"
788:
789: "decl %4\n"
790: "jnz 0b\n"
791: "1:\n"
792:
793: /* final run */
794: /* set the current, current_pre, current_next registers */
795: "movq (%1), %%mm1\n"
796: "movq (%1), %%mm7\n"
797: "movq -8(%1), %%mm0\n"
798: "psrlq $32, %%mm1\n"
799: "psrlq $32, %%mm0\n"
800: "psllq $32, %%mm1\n"
801: "movq %%mm7, %%mm2\n"
802: "movq %%mm7, %%mm3\n"
803: "psllq $32, %%mm2\n"
804: "psrlq $32, %%mm3\n"
805: "por %%mm2, %%mm0\n"
806: "por %%mm3, %%mm1\n"
807:
808: /* current_upper */
809: "movq (%0), %%mm6\n"
810:
811: /* compute the upper-left pixel for dst on %%mm2 */
812: /* compute the upper-right pixel for dst on %%mm4 */
813: "movq %%mm0, %%mm2\n"
814: "movq %%mm1, %%mm4\n"
815: "movq %%mm0, %%mm3\n"
816: "movq %%mm1, %%mm5\n"
817: "pcmpeqd %%mm6, %%mm2\n"
818: "pcmpeqd %%mm6, %%mm4\n"
819: "pcmpeqd (%2), %%mm3\n"
820: "pcmpeqd (%2), %%mm5\n"
821: "pandn %%mm2, %%mm3\n"
822: "pandn %%mm4, %%mm5\n"
823: "movq %%mm0, %%mm2\n"
824: "movq %%mm1, %%mm4\n"
825: "pcmpeqd %%mm1, %%mm2\n"
826: "pcmpeqd %%mm0, %%mm4\n"
827: "pandn %%mm3, %%mm2\n"
828: "pandn %%mm5, %%mm4\n"
829: "movq %%mm2, %%mm3\n"
830: "movq %%mm4, %%mm5\n"
831: "pand %%mm6, %%mm2\n"
832: "pand %%mm6, %%mm4\n"
833: "pandn %%mm7, %%mm3\n"
834: "pandn %%mm7, %%mm5\n"
835: "por %%mm3, %%mm2\n"
836: "por %%mm5, %%mm4\n"
837:
838: /* set *dst */
839: "movq %%mm2, %%mm3\n"
840: "punpckldq %%mm4, %%mm2\n"
841: "punpckhdq %%mm4, %%mm3\n"
842: "movq %%mm2, (%3)\n"
843: "movq %%mm3, 8(%3)\n"
844:
845: : "+r" (src0), "+r" (src1), "+r" (src2), "+r" (dst), "+r" (count)
846: :
847: : "cc"
848: );
849: }
850:
851: /**
852: * Scale by a factor of 2 a row of pixels of 8 bits.
853: * This is a very fast MMX implementation.
854: * The implementation uses a combination of cmp/and/not operations to
855: * completly remove the need of conditional jumps. This trick give the
856: * major speed improvement.
857: * Also, using the 8 bytes MMX registers more than one pixel are computed
858: * at the same time.
859: * Before calling this function you must ensure that the currenct CPU supports
860: * the MMX instruction set. After calling it you must be sure to call the EMMS
861: * instruction before any floating-point operation.
862: * The pixels over the left and right borders are assumed of the same color of
863: * the pixels on the border.
864: * \param src0 Pointer at the first pixel of the previous row.
865: * \param src1 Pointer at the first pixel of the current row.
866: * \param src2 Pointer at the first pixel of the next row.
867: * \param count Length in pixels of the src0, src1 and src2 rows. It must
868: * be at least 16 and a multiple of 8.
869: * \param dst0 First destination row, double length in pixels.
870: * \param dst1 Second destination row, double length in pixels.
871: */
872: static void scale2x_8_mmx(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
873: {
874: assert(count >= 16);
875: assert(count % 8 == 0);
876:
877: scale2x_8_mmx_single(dst0, src0, src1, src2, count);
878: scale2x_8_mmx_single(dst1, src2, src1, src0, count);
879: }
880:
881: /**
882: * Scale by a factor of 2 a row of pixels of 16 bits.
883: * This function operates like scale2x_8_mmx() but for 16 bits pixels.
884: * \param src0 Pointer at the first pixel of the previous row.
885: * \param src1 Pointer at the first pixel of the current row.
886: * \param src2 Pointer at the first pixel of the next row.
887: * \param count Length in pixels of the src0, src1 and src2 rows. It must
888: * be at least 8 and a multiple of 4.
889: * \param dst0 First destination row, double length in pixels.
890: * \param dst1 Second destination row, double length in pixels.
891: */
892: static void scale2x_16_mmx(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
893: {
894: assert(count >= 8);
895: assert(count % 4 == 0);
896:
897: scale2x_16_mmx_single(dst0, src0, src1, src2, count);
898: scale2x_16_mmx_single(dst1, src2, src1, src0, count);
899: }
900:
901: /**
902: * Scale by a factor of 2 a row of pixels of 32 bits.
903: * This function operates like scale2x_8_mmx() but for 32 bits pixels.
904: * \param src0 Pointer at the first pixel of the previous row.
905: * \param src1 Pointer at the first pixel of the current row.
906: * \param src2 Pointer at the first pixel of the next row.
907: * \param count Length in pixels of the src0, src1 and src2 rows. It must
908: * be at least 4 and a multiple of 2.
909: * \param dst0 First destination row, double length in pixels.
910: * \param dst1 Second destination row, double length in pixels.
911: */
912: static void scale2x_32_mmx(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
913: {
914: assert(count >= 4);
915: assert(count % 2 == 0);
916:
917: scale2x_32_mmx_single(dst0, src0, src1, src2, count);
918: scale2x_32_mmx_single(dst1, src2, src1, src0, count);
919: }
920:
921: /**
922: * End the use of the MMX instructions.
923: * This function must be called before using any floating-point operations.
924: */
925: static inline void scale2x_mmx_emms(void)
926: {
927: __asm__ __volatile__ (
928: "emms"
929: );
930: }
931:
932: #endif
933:
934: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.