Merge commit 'fab9df63a3156ffe1f9490aafaea41e03ef60ddf'
[ffmpeg.git] / libavcodec / x86 / dsputil_mmx.c
1 /*
2  * MMX optimized DSP utils
3  * Copyright (c) 2000, 2001 Fabrice Bellard
4  * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  * MMX optimization by Nick Kurshev <nickols_k@mail.ru>
23  */
24
25 #include "config.h"
26 #include "libavutil/avassert.h"
27 #include "libavutil/cpu.h"
28 #include "libavutil/x86/asm.h"
29 #include "libavcodec/pixels.h"
30 #include "libavcodec/videodsp.h"
31 #include "dsputil_x86.h"
32 #include "inline_asm.h"
33
34 #if HAVE_INLINE_ASM
35
36 void ff_put_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels,
37                                int line_size)
38 {
39     const int16_t *p;
40     uint8_t *pix;
41
42     /* read the pixels */
43     p   = block;
44     pix = pixels;
45     /* unrolled loop */
46     __asm__ volatile (
47         "movq      (%3), %%mm0          \n\t"
48         "movq     8(%3), %%mm1          \n\t"
49         "movq    16(%3), %%mm2          \n\t"
50         "movq    24(%3), %%mm3          \n\t"
51         "movq    32(%3), %%mm4          \n\t"
52         "movq    40(%3), %%mm5          \n\t"
53         "movq    48(%3), %%mm6          \n\t"
54         "movq    56(%3), %%mm7          \n\t"
55         "packuswb %%mm1, %%mm0          \n\t"
56         "packuswb %%mm3, %%mm2          \n\t"
57         "packuswb %%mm5, %%mm4          \n\t"
58         "packuswb %%mm7, %%mm6          \n\t"
59         "movq     %%mm0, (%0)           \n\t"
60         "movq     %%mm2, (%0, %1)       \n\t"
61         "movq     %%mm4, (%0, %1, 2)    \n\t"
62         "movq     %%mm6, (%0, %2)       \n\t"
63         :: "r" (pix), "r" ((x86_reg) line_size), "r" ((x86_reg) line_size * 3),
64            "r" (p)
65         : "memory");
66     pix += line_size * 4;
67     p   += 32;
68
69     // if here would be an exact copy of the code above
70     // compiler would generate some very strange code
71     // thus using "r"
72     __asm__ volatile (
73         "movq       (%3), %%mm0         \n\t"
74         "movq      8(%3), %%mm1         \n\t"
75         "movq     16(%3), %%mm2         \n\t"
76         "movq     24(%3), %%mm3         \n\t"
77         "movq     32(%3), %%mm4         \n\t"
78         "movq     40(%3), %%mm5         \n\t"
79         "movq     48(%3), %%mm6         \n\t"
80         "movq     56(%3), %%mm7         \n\t"
81         "packuswb  %%mm1, %%mm0         \n\t"
82         "packuswb  %%mm3, %%mm2         \n\t"
83         "packuswb  %%mm5, %%mm4         \n\t"
84         "packuswb  %%mm7, %%mm6         \n\t"
85         "movq      %%mm0, (%0)          \n\t"
86         "movq      %%mm2, (%0, %1)      \n\t"
87         "movq      %%mm4, (%0, %1, 2)   \n\t"
88         "movq      %%mm6, (%0, %2)      \n\t"
89         :: "r" (pix), "r" ((x86_reg) line_size), "r" ((x86_reg) line_size * 3),
90            "r" (p)
91         : "memory");
92 }
93
94 void ff_add_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels,
95                                int line_size)
96 {
97     const int16_t *p;
98     uint8_t *pix;
99     int i;
100
101     /* read the pixels */
102     p   = block;
103     pix = pixels;
104     MOVQ_ZERO(mm7);
105     i = 4;
106     do {
107         __asm__ volatile (
108             "movq        (%2), %%mm0    \n\t"
109             "movq       8(%2), %%mm1    \n\t"
110             "movq      16(%2), %%mm2    \n\t"
111             "movq      24(%2), %%mm3    \n\t"
112             "movq          %0, %%mm4    \n\t"
113             "movq          %1, %%mm6    \n\t"
114             "movq       %%mm4, %%mm5    \n\t"
115             "punpcklbw  %%mm7, %%mm4    \n\t"
116             "punpckhbw  %%mm7, %%mm5    \n\t"
117             "paddsw     %%mm4, %%mm0    \n\t"
118             "paddsw     %%mm5, %%mm1    \n\t"
119             "movq       %%mm6, %%mm5    \n\t"
120             "punpcklbw  %%mm7, %%mm6    \n\t"
121             "punpckhbw  %%mm7, %%mm5    \n\t"
122             "paddsw     %%mm6, %%mm2    \n\t"
123             "paddsw     %%mm5, %%mm3    \n\t"
124             "packuswb   %%mm1, %%mm0    \n\t"
125             "packuswb   %%mm3, %%mm2    \n\t"
126             "movq       %%mm0, %0       \n\t"
127             "movq       %%mm2, %1       \n\t"
128             : "+m" (*pix), "+m" (*(pix + line_size))
129             : "r" (p)
130             : "memory");
131         pix += line_size * 2;
132         p   += 16;
133     } while (--i);
134 }
135
136 /* Draw the edges of width 'w' of an image of size width, height
137  * this MMX version can only handle w == 8 || w == 16. */
138 void ff_draw_edges_mmx(uint8_t *buf, int wrap, int width, int height,
139                        int w, int h, int sides)
140 {
141     uint8_t *ptr, *last_line;
142     int i;
143
144     last_line = buf + (height - 1) * wrap;
145     /* left and right */
146     ptr = buf;
147     if (w == 8) {
148         __asm__ volatile (
149             "1:                             \n\t"
150             "movd            (%0), %%mm0    \n\t"
151             "punpcklbw      %%mm0, %%mm0    \n\t"
152             "punpcklwd      %%mm0, %%mm0    \n\t"
153             "punpckldq      %%mm0, %%mm0    \n\t"
154             "movq           %%mm0, -8(%0)   \n\t"
155             "movq      -8(%0, %2), %%mm1    \n\t"
156             "punpckhbw      %%mm1, %%mm1    \n\t"
157             "punpckhwd      %%mm1, %%mm1    \n\t"
158             "punpckhdq      %%mm1, %%mm1    \n\t"
159             "movq           %%mm1, (%0, %2) \n\t"
160             "add               %1, %0       \n\t"
161             "cmp               %3, %0       \n\t"
162             "jb                1b           \n\t"
163             : "+r" (ptr)
164             : "r" ((x86_reg) wrap), "r" ((x86_reg) width),
165               "r" (ptr + wrap * height));
166     } else if (w == 16) {
167         __asm__ volatile (
168             "1:                                 \n\t"
169             "movd            (%0), %%mm0        \n\t"
170             "punpcklbw      %%mm0, %%mm0        \n\t"
171             "punpcklwd      %%mm0, %%mm0        \n\t"
172             "punpckldq      %%mm0, %%mm0        \n\t"
173             "movq           %%mm0, -8(%0)       \n\t"
174             "movq           %%mm0, -16(%0)      \n\t"
175             "movq      -8(%0, %2), %%mm1        \n\t"
176             "punpckhbw      %%mm1, %%mm1        \n\t"
177             "punpckhwd      %%mm1, %%mm1        \n\t"
178             "punpckhdq      %%mm1, %%mm1        \n\t"
179             "movq           %%mm1,  (%0, %2)    \n\t"
180             "movq           %%mm1, 8(%0, %2)    \n\t"
181             "add               %1, %0           \n\t"
182             "cmp               %3, %0           \n\t"
183             "jb                1b               \n\t"
184             : "+r"(ptr)
185             : "r"((x86_reg)wrap), "r"((x86_reg)width), "r"(ptr + wrap * height)
186             );
187     } else {
188         av_assert1(w == 4);
189         __asm__ volatile (
190             "1:                             \n\t"
191             "movd            (%0), %%mm0    \n\t"
192             "punpcklbw      %%mm0, %%mm0    \n\t"
193             "punpcklwd      %%mm0, %%mm0    \n\t"
194             "movd           %%mm0, -4(%0)   \n\t"
195             "movd      -4(%0, %2), %%mm1    \n\t"
196             "punpcklbw      %%mm1, %%mm1    \n\t"
197             "punpckhwd      %%mm1, %%mm1    \n\t"
198             "punpckhdq      %%mm1, %%mm1    \n\t"
199             "movd           %%mm1, (%0, %2) \n\t"
200             "add               %1, %0       \n\t"
201             "cmp               %3, %0       \n\t"
202             "jb                1b           \n\t"
203             : "+r" (ptr)
204             : "r" ((x86_reg) wrap), "r" ((x86_reg) width),
205               "r" (ptr + wrap * height));
206     }
207
208     /* top and bottom (and hopefully also the corners) */
209     if (sides & EDGE_TOP) {
210         for (i = 0; i < h; i += 4) {
211             ptr = buf - (i + 1) * wrap - w;
212             __asm__ volatile (
213                 "1:                             \n\t"
214                 "movq (%1, %0), %%mm0           \n\t"
215                 "movq    %%mm0, (%0)            \n\t"
216                 "movq    %%mm0, (%0, %2)        \n\t"
217                 "movq    %%mm0, (%0, %2, 2)     \n\t"
218                 "movq    %%mm0, (%0, %3)        \n\t"
219                 "add        $8, %0              \n\t"
220                 "cmp        %4, %0              \n\t"
221                 "jb         1b                  \n\t"
222                 : "+r" (ptr)
223                 : "r" ((x86_reg) buf - (x86_reg) ptr - w),
224                   "r" ((x86_reg) - wrap), "r" ((x86_reg) - wrap * 3),
225                   "r" (ptr + width + 2 * w));
226         }
227     }
228
229     if (sides & EDGE_BOTTOM) {
230         for (i = 0; i < h; i += 4) {
231             ptr = last_line + (i + 1) * wrap - w;
232             __asm__ volatile (
233                 "1:                             \n\t"
234                 "movq (%1, %0), %%mm0           \n\t"
235                 "movq    %%mm0, (%0)            \n\t"
236                 "movq    %%mm0, (%0, %2)        \n\t"
237                 "movq    %%mm0, (%0, %2, 2)     \n\t"
238                 "movq    %%mm0, (%0, %3)        \n\t"
239                 "add        $8, %0              \n\t"
240                 "cmp        %4, %0              \n\t"
241                 "jb         1b                  \n\t"
242                 : "+r" (ptr)
243                 : "r" ((x86_reg) last_line - (x86_reg) ptr - w),
244                   "r" ((x86_reg) wrap), "r" ((x86_reg) wrap * 3),
245                   "r" (ptr + width + 2 * w));
246         }
247     }
248 }
249
250 #endif /* HAVE_INLINE_ASM */