Merge commit '01c5779f56cf708e6cb88b11cfdc248cae7e2ee8'
[ffmpeg.git] / libavcodec / x86 / dsputilenc_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  * MMX optimization by Nick Kurshev <nickols_k@mail.ru>
7  *
8  * This file is part of FFmpeg.
9  *
10  * FFmpeg is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * FFmpeg is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with FFmpeg; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  */
24
25 #include "libavutil/attributes.h"
26 #include "libavutil/cpu.h"
27 #include "libavutil/x86/asm.h"
28 #include "libavutil/x86/cpu.h"
29 #include "libavcodec/dct.h"
30 #include "libavcodec/dsputil.h"
31 #include "libavcodec/mpegvideo.h"
32 #include "libavcodec/mathops.h"
33 #include "dsputil_x86.h"
34
35 void ff_get_pixels_mmx(int16_t *block, const uint8_t *pixels, int line_size);
36 void ff_get_pixels_sse2(int16_t *block, const uint8_t *pixels, int line_size);
37 void ff_diff_pixels_mmx(int16_t *block, const uint8_t *s1, const uint8_t *s2,
38                         int stride);
39 int ff_pix_sum16_mmx(uint8_t *pix, int line_size);
40 int ff_pix_norm1_mmx(uint8_t *pix, int line_size);
41
42 #if HAVE_INLINE_ASM
43
44 static int sse8_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
45                     int line_size, int h)
46 {
47     int tmp;
48
49     __asm__ volatile (
50         "movl         %4, %%ecx          \n"
51         "shr          $1, %%ecx          \n"
52         "pxor      %%mm0, %%mm0          \n" /* mm0 = 0 */
53         "pxor      %%mm7, %%mm7          \n" /* mm7 holds the sum */
54         "1:                              \n"
55         "movq       (%0), %%mm1          \n" /* mm1 = pix1[0][0 - 7] */
56         "movq       (%1), %%mm2          \n" /* mm2 = pix2[0][0 - 7] */
57         "movq   (%0, %3), %%mm3          \n" /* mm3 = pix1[1][0 - 7] */
58         "movq   (%1, %3), %%mm4          \n" /* mm4 = pix2[1][0 - 7] */
59
60         /* todo: mm1-mm2, mm3-mm4 */
61         /* algo: subtract mm1 from mm2 with saturation and vice versa */
62         /*       OR the results to get absolute difference */
63         "movq      %%mm1, %%mm5          \n"
64         "movq      %%mm3, %%mm6          \n"
65         "psubusb   %%mm2, %%mm1          \n"
66         "psubusb   %%mm4, %%mm3          \n"
67         "psubusb   %%mm5, %%mm2          \n"
68         "psubusb   %%mm6, %%mm4          \n"
69
70         "por       %%mm1, %%mm2          \n"
71         "por       %%mm3, %%mm4          \n"
72
73         /* now convert to 16-bit vectors so we can square them */
74         "movq      %%mm2, %%mm1          \n"
75         "movq      %%mm4, %%mm3          \n"
76
77         "punpckhbw %%mm0, %%mm2          \n"
78         "punpckhbw %%mm0, %%mm4          \n"
79         "punpcklbw %%mm0, %%mm1          \n" /* mm1 now spread over (mm1, mm2) */
80         "punpcklbw %%mm0, %%mm3          \n" /* mm4 now spread over (mm3, mm4) */
81
82         "pmaddwd   %%mm2, %%mm2          \n"
83         "pmaddwd   %%mm4, %%mm4          \n"
84         "pmaddwd   %%mm1, %%mm1          \n"
85         "pmaddwd   %%mm3, %%mm3          \n"
86
87         "lea (%0, %3, 2), %0             \n" /* pix1 += 2 * line_size */
88         "lea (%1, %3, 2), %1             \n" /* pix2 += 2 * line_size */
89
90         "paddd     %%mm2, %%mm1          \n"
91         "paddd     %%mm4, %%mm3          \n"
92         "paddd     %%mm1, %%mm7          \n"
93         "paddd     %%mm3, %%mm7          \n"
94
95         "decl      %%ecx                 \n"
96         "jnz       1b                    \n"
97
98         "movq      %%mm7, %%mm1          \n"
99         "psrlq       $32, %%mm7          \n" /* shift hi dword to lo */
100         "paddd     %%mm7, %%mm1          \n"
101         "movd      %%mm1, %2             \n"
102         : "+r" (pix1), "+r" (pix2), "=r" (tmp)
103         : "r" ((x86_reg) line_size), "m" (h)
104         : "%ecx");
105
106     return tmp;
107 }
108
109 static int sse16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
110                      int line_size, int h)
111 {
112     int tmp;
113
114     __asm__ volatile (
115         "movl %4, %%ecx\n"
116         "pxor %%mm0, %%mm0\n"    /* mm0 = 0 */
117         "pxor %%mm7, %%mm7\n"    /* mm7 holds the sum */
118         "1:\n"
119         "movq (%0), %%mm1\n"     /* mm1 = pix1[0 -  7] */
120         "movq (%1), %%mm2\n"     /* mm2 = pix2[0 -  7] */
121         "movq 8(%0), %%mm3\n"    /* mm3 = pix1[8 - 15] */
122         "movq 8(%1), %%mm4\n"    /* mm4 = pix2[8 - 15] */
123
124         /* todo: mm1-mm2, mm3-mm4 */
125         /* algo: subtract mm1 from mm2 with saturation and vice versa */
126         /*       OR the results to get absolute difference */
127         "movq %%mm1, %%mm5\n"
128         "movq %%mm3, %%mm6\n"
129         "psubusb %%mm2, %%mm1\n"
130         "psubusb %%mm4, %%mm3\n"
131         "psubusb %%mm5, %%mm2\n"
132         "psubusb %%mm6, %%mm4\n"
133
134         "por %%mm1, %%mm2\n"
135         "por %%mm3, %%mm4\n"
136
137         /* now convert to 16-bit vectors so we can square them */
138         "movq %%mm2, %%mm1\n"
139         "movq %%mm4, %%mm3\n"
140
141         "punpckhbw %%mm0, %%mm2\n"
142         "punpckhbw %%mm0, %%mm4\n"
143         "punpcklbw %%mm0, %%mm1\n" /* mm1 now spread over (mm1, mm2) */
144         "punpcklbw %%mm0, %%mm3\n" /* mm4 now spread over (mm3, mm4) */
145
146         "pmaddwd %%mm2, %%mm2\n"
147         "pmaddwd %%mm4, %%mm4\n"
148         "pmaddwd %%mm1, %%mm1\n"
149         "pmaddwd %%mm3, %%mm3\n"
150
151         "add %3, %0\n"
152         "add %3, %1\n"
153
154         "paddd %%mm2, %%mm1\n"
155         "paddd %%mm4, %%mm3\n"
156         "paddd %%mm1, %%mm7\n"
157         "paddd %%mm3, %%mm7\n"
158
159         "decl %%ecx\n"
160         "jnz 1b\n"
161
162         "movq %%mm7, %%mm1\n"
163         "psrlq $32, %%mm7\n"    /* shift hi dword to lo */
164         "paddd %%mm7, %%mm1\n"
165         "movd %%mm1, %2\n"
166         : "+r" (pix1), "+r" (pix2), "=r" (tmp)
167         : "r" ((x86_reg) line_size), "m" (h)
168         : "%ecx");
169
170     return tmp;
171 }
172
173 static int hf_noise8_mmx(uint8_t *pix1, int line_size, int h)
174 {
175     int tmp;
176
177     __asm__ volatile (
178         "movl %3, %%ecx\n"
179         "pxor %%mm7, %%mm7\n"
180         "pxor %%mm6, %%mm6\n"
181
182         "movq (%0), %%mm0\n"
183         "movq %%mm0, %%mm1\n"
184         "psllq $8, %%mm0\n"
185         "psrlq $8, %%mm1\n"
186         "psrlq $8, %%mm0\n"
187         "movq %%mm0, %%mm2\n"
188         "movq %%mm1, %%mm3\n"
189         "punpcklbw %%mm7, %%mm0\n"
190         "punpcklbw %%mm7, %%mm1\n"
191         "punpckhbw %%mm7, %%mm2\n"
192         "punpckhbw %%mm7, %%mm3\n"
193         "psubw %%mm1, %%mm0\n"
194         "psubw %%mm3, %%mm2\n"
195
196         "add %2, %0\n"
197
198         "movq (%0), %%mm4\n"
199         "movq %%mm4, %%mm1\n"
200         "psllq $8, %%mm4\n"
201         "psrlq $8, %%mm1\n"
202         "psrlq $8, %%mm4\n"
203         "movq %%mm4, %%mm5\n"
204         "movq %%mm1, %%mm3\n"
205         "punpcklbw %%mm7, %%mm4\n"
206         "punpcklbw %%mm7, %%mm1\n"
207         "punpckhbw %%mm7, %%mm5\n"
208         "punpckhbw %%mm7, %%mm3\n"
209         "psubw %%mm1, %%mm4\n"
210         "psubw %%mm3, %%mm5\n"
211         "psubw %%mm4, %%mm0\n"
212         "psubw %%mm5, %%mm2\n"
213         "pxor %%mm3, %%mm3\n"
214         "pxor %%mm1, %%mm1\n"
215         "pcmpgtw %%mm0, %%mm3\n\t"
216         "pcmpgtw %%mm2, %%mm1\n\t"
217         "pxor %%mm3, %%mm0\n"
218         "pxor %%mm1, %%mm2\n"
219         "psubw %%mm3, %%mm0\n"
220         "psubw %%mm1, %%mm2\n"
221         "paddw %%mm0, %%mm2\n"
222         "paddw %%mm2, %%mm6\n"
223
224         "add %2, %0\n"
225         "1:\n"
226
227         "movq (%0), %%mm0\n"
228         "movq %%mm0, %%mm1\n"
229         "psllq $8, %%mm0\n"
230         "psrlq $8, %%mm1\n"
231         "psrlq $8, %%mm0\n"
232         "movq %%mm0, %%mm2\n"
233         "movq %%mm1, %%mm3\n"
234         "punpcklbw %%mm7, %%mm0\n"
235         "punpcklbw %%mm7, %%mm1\n"
236         "punpckhbw %%mm7, %%mm2\n"
237         "punpckhbw %%mm7, %%mm3\n"
238         "psubw %%mm1, %%mm0\n"
239         "psubw %%mm3, %%mm2\n"
240         "psubw %%mm0, %%mm4\n"
241         "psubw %%mm2, %%mm5\n"
242         "pxor  %%mm3, %%mm3\n"
243         "pxor  %%mm1, %%mm1\n"
244         "pcmpgtw %%mm4, %%mm3\n\t"
245         "pcmpgtw %%mm5, %%mm1\n\t"
246         "pxor  %%mm3, %%mm4\n"
247         "pxor  %%mm1, %%mm5\n"
248         "psubw %%mm3, %%mm4\n"
249         "psubw %%mm1, %%mm5\n"
250         "paddw %%mm4, %%mm5\n"
251         "paddw %%mm5, %%mm6\n"
252
253         "add %2, %0\n"
254
255         "movq (%0), %%mm4\n"
256         "movq      %%mm4, %%mm1\n"
257         "psllq $8, %%mm4\n"
258         "psrlq $8, %%mm1\n"
259         "psrlq $8, %%mm4\n"
260         "movq      %%mm4, %%mm5\n"
261         "movq      %%mm1, %%mm3\n"
262         "punpcklbw %%mm7, %%mm4\n"
263         "punpcklbw %%mm7, %%mm1\n"
264         "punpckhbw %%mm7, %%mm5\n"
265         "punpckhbw %%mm7, %%mm3\n"
266         "psubw     %%mm1, %%mm4\n"
267         "psubw     %%mm3, %%mm5\n"
268         "psubw     %%mm4, %%mm0\n"
269         "psubw     %%mm5, %%mm2\n"
270         "pxor      %%mm3, %%mm3\n"
271         "pxor      %%mm1, %%mm1\n"
272         "pcmpgtw   %%mm0, %%mm3\n\t"
273         "pcmpgtw   %%mm2, %%mm1\n\t"
274         "pxor      %%mm3, %%mm0\n"
275         "pxor      %%mm1, %%mm2\n"
276         "psubw     %%mm3, %%mm0\n"
277         "psubw     %%mm1, %%mm2\n"
278         "paddw     %%mm0, %%mm2\n"
279         "paddw     %%mm2, %%mm6\n"
280
281         "add  %2, %0\n"
282         "subl $2, %%ecx\n"
283         " jnz 1b\n"
284
285         "movq      %%mm6, %%mm0\n"
286         "punpcklwd %%mm7, %%mm0\n"
287         "punpckhwd %%mm7, %%mm6\n"
288         "paddd     %%mm0, %%mm6\n"
289
290         "movq  %%mm6, %%mm0\n"
291         "psrlq $32,   %%mm6\n"
292         "paddd %%mm6, %%mm0\n"
293         "movd  %%mm0, %1\n"
294         : "+r" (pix1), "=r" (tmp)
295         : "r" ((x86_reg) line_size), "g" (h - 2)
296         : "%ecx");
297
298     return tmp;
299 }
300
301 static int hf_noise16_mmx(uint8_t *pix1, int line_size, int h)
302 {
303     int tmp;
304     uint8_t *pix = pix1;
305
306     __asm__ volatile (
307         "movl %3, %%ecx\n"
308         "pxor %%mm7, %%mm7\n"
309         "pxor %%mm6, %%mm6\n"
310
311         "movq (%0), %%mm0\n"
312         "movq 1(%0), %%mm1\n"
313         "movq %%mm0, %%mm2\n"
314         "movq %%mm1, %%mm3\n"
315         "punpcklbw %%mm7, %%mm0\n"
316         "punpcklbw %%mm7, %%mm1\n"
317         "punpckhbw %%mm7, %%mm2\n"
318         "punpckhbw %%mm7, %%mm3\n"
319         "psubw %%mm1, %%mm0\n"
320         "psubw %%mm3, %%mm2\n"
321
322         "add %2, %0\n"
323
324         "movq (%0), %%mm4\n"
325         "movq 1(%0), %%mm1\n"
326         "movq %%mm4, %%mm5\n"
327         "movq %%mm1, %%mm3\n"
328         "punpcklbw %%mm7, %%mm4\n"
329         "punpcklbw %%mm7, %%mm1\n"
330         "punpckhbw %%mm7, %%mm5\n"
331         "punpckhbw %%mm7, %%mm3\n"
332         "psubw %%mm1, %%mm4\n"
333         "psubw %%mm3, %%mm5\n"
334         "psubw %%mm4, %%mm0\n"
335         "psubw %%mm5, %%mm2\n"
336         "pxor %%mm3, %%mm3\n"
337         "pxor %%mm1, %%mm1\n"
338         "pcmpgtw %%mm0, %%mm3\n\t"
339         "pcmpgtw %%mm2, %%mm1\n\t"
340         "pxor %%mm3, %%mm0\n"
341         "pxor %%mm1, %%mm2\n"
342         "psubw %%mm3, %%mm0\n"
343         "psubw %%mm1, %%mm2\n"
344         "paddw %%mm0, %%mm2\n"
345         "paddw %%mm2, %%mm6\n"
346
347         "add %2, %0\n"
348         "1:\n"
349
350         "movq (%0), %%mm0\n"
351         "movq 1(%0), %%mm1\n"
352         "movq %%mm0, %%mm2\n"
353         "movq %%mm1, %%mm3\n"
354         "punpcklbw %%mm7, %%mm0\n"
355         "punpcklbw %%mm7, %%mm1\n"
356         "punpckhbw %%mm7, %%mm2\n"
357         "punpckhbw %%mm7, %%mm3\n"
358         "psubw %%mm1, %%mm0\n"
359         "psubw %%mm3, %%mm2\n"
360         "psubw %%mm0, %%mm4\n"
361         "psubw %%mm2, %%mm5\n"
362         "pxor %%mm3, %%mm3\n"
363         "pxor %%mm1, %%mm1\n"
364         "pcmpgtw %%mm4, %%mm3\n\t"
365         "pcmpgtw %%mm5, %%mm1\n\t"
366         "pxor %%mm3, %%mm4\n"
367         "pxor %%mm1, %%mm5\n"
368         "psubw %%mm3, %%mm4\n"
369         "psubw %%mm1, %%mm5\n"
370         "paddw %%mm4, %%mm5\n"
371         "paddw %%mm5, %%mm6\n"
372
373         "add %2, %0\n"
374
375         "movq (%0), %%mm4\n"
376         "movq 1(%0), %%mm1\n"
377         "movq %%mm4, %%mm5\n"
378         "movq %%mm1, %%mm3\n"
379         "punpcklbw %%mm7, %%mm4\n"
380         "punpcklbw %%mm7, %%mm1\n"
381         "punpckhbw %%mm7, %%mm5\n"
382         "punpckhbw %%mm7, %%mm3\n"
383         "psubw %%mm1, %%mm4\n"
384         "psubw %%mm3, %%mm5\n"
385         "psubw %%mm4, %%mm0\n"
386         "psubw %%mm5, %%mm2\n"
387         "pxor %%mm3, %%mm3\n"
388         "pxor %%mm1, %%mm1\n"
389         "pcmpgtw %%mm0, %%mm3\n\t"
390         "pcmpgtw %%mm2, %%mm1\n\t"
391         "pxor %%mm3, %%mm0\n"
392         "pxor %%mm1, %%mm2\n"
393         "psubw %%mm3, %%mm0\n"
394         "psubw %%mm1, %%mm2\n"
395         "paddw %%mm0, %%mm2\n"
396         "paddw %%mm2, %%mm6\n"
397
398         "add %2, %0\n"
399         "subl $2, %%ecx\n"
400         " jnz 1b\n"
401
402         "movq %%mm6, %%mm0\n"
403         "punpcklwd %%mm7, %%mm0\n"
404         "punpckhwd %%mm7, %%mm6\n"
405         "paddd %%mm0, %%mm6\n"
406
407         "movq %%mm6, %%mm0\n"
408         "psrlq $32, %%mm6\n"
409         "paddd %%mm6, %%mm0\n"
410         "movd %%mm0, %1\n"
411         : "+r" (pix1), "=r" (tmp)
412         : "r" ((x86_reg) line_size), "g" (h - 2)
413         : "%ecx");
414
415     return tmp + hf_noise8_mmx(pix + 8, line_size, h);
416 }
417
418 static int nsse16_mmx(MpegEncContext *c, uint8_t *pix1, uint8_t *pix2,
419                       int line_size, int h)
420 {
421     int score1, score2;
422
423     if (c)
424         score1 = c->dsp.sse[0](c, pix1, pix2, line_size, h);
425     else
426         score1 = sse16_mmx(c, pix1, pix2, line_size, h);
427     score2 = hf_noise16_mmx(pix1, line_size, h) -
428              hf_noise16_mmx(pix2, line_size, h);
429
430     if (c)
431         return score1 + FFABS(score2) * c->avctx->nsse_weight;
432     else
433         return score1 + FFABS(score2) * 8;
434 }
435
436 static int nsse8_mmx(MpegEncContext *c, uint8_t *pix1, uint8_t *pix2,
437                      int line_size, int h)
438 {
439     int score1 = sse8_mmx(c, pix1, pix2, line_size, h);
440     int score2 = hf_noise8_mmx(pix1, line_size, h) -
441                  hf_noise8_mmx(pix2, line_size, h);
442
443     if (c)
444         return score1 + FFABS(score2) * c->avctx->nsse_weight;
445     else
446         return score1 + FFABS(score2) * 8;
447 }
448
449 static int vsad_intra16_mmx(MpegEncContext *v, uint8_t *pix, uint8_t *dummy,
450                             int line_size, int h)
451 {
452     int tmp;
453
454     av_assert2((((int) pix) & 7) == 0);
455     av_assert2((line_size & 7) == 0);
456
457 #define SUM(in0, in1, out0, out1)               \
458     "movq (%0), %%mm2\n"                        \
459     "movq 8(%0), %%mm3\n"                       \
460     "add %2,%0\n"                               \
461     "movq %%mm2, " #out0 "\n"                   \
462     "movq %%mm3, " #out1 "\n"                   \
463     "psubusb " #in0 ", %%mm2\n"                 \
464     "psubusb " #in1 ", %%mm3\n"                 \
465     "psubusb " #out0 ", " #in0 "\n"             \
466     "psubusb " #out1 ", " #in1 "\n"             \
467     "por %%mm2, " #in0 "\n"                     \
468     "por %%mm3, " #in1 "\n"                     \
469     "movq " #in0 ", %%mm2\n"                    \
470     "movq " #in1 ", %%mm3\n"                    \
471     "punpcklbw %%mm7, " #in0 "\n"               \
472     "punpcklbw %%mm7, " #in1 "\n"               \
473     "punpckhbw %%mm7, %%mm2\n"                  \
474     "punpckhbw %%mm7, %%mm3\n"                  \
475     "paddw " #in1 ", " #in0 "\n"                \
476     "paddw %%mm3, %%mm2\n"                      \
477     "paddw %%mm2, " #in0 "\n"                   \
478     "paddw " #in0 ", %%mm6\n"
479
480
481     __asm__ volatile (
482         "movl    %3, %%ecx\n"
483         "pxor %%mm6, %%mm6\n"
484         "pxor %%mm7, %%mm7\n"
485         "movq  (%0), %%mm0\n"
486         "movq 8(%0), %%mm1\n"
487         "add %2, %0\n"
488         "jmp 2f\n"
489         "1:\n"
490
491         SUM(%%mm4, %%mm5, %%mm0, %%mm1)
492         "2:\n"
493         SUM(%%mm0, %%mm1, %%mm4, %%mm5)
494
495         "subl $2, %%ecx\n"
496         "jnz 1b\n"
497
498         "movq  %%mm6, %%mm0\n"
499         "psrlq $32,   %%mm6\n"
500         "paddw %%mm6, %%mm0\n"
501         "movq  %%mm0, %%mm6\n"
502         "psrlq $16,   %%mm0\n"
503         "paddw %%mm6, %%mm0\n"
504         "movd  %%mm0, %1\n"
505         : "+r" (pix), "=r" (tmp)
506         : "r" ((x86_reg) line_size), "m" (h)
507         : "%ecx");
508
509     return tmp & 0xFFFF;
510 }
511 #undef SUM
512
513 static int vsad_intra16_mmxext(MpegEncContext *v, uint8_t *pix, uint8_t *dummy,
514                                int line_size, int h)
515 {
516     int tmp;
517
518     av_assert2((((int) pix) & 7) == 0);
519     av_assert2((line_size & 7) == 0);
520
521 #define SUM(in0, in1, out0, out1)               \
522     "movq (%0), " #out0 "\n"                    \
523     "movq 8(%0), " #out1 "\n"                   \
524     "add %2, %0\n"                              \
525     "psadbw " #out0 ", " #in0 "\n"              \
526     "psadbw " #out1 ", " #in1 "\n"              \
527     "paddw " #in1 ", " #in0 "\n"                \
528     "paddw " #in0 ", %%mm6\n"
529
530     __asm__ volatile (
531         "movl %3, %%ecx\n"
532         "pxor %%mm6, %%mm6\n"
533         "pxor %%mm7, %%mm7\n"
534         "movq (%0), %%mm0\n"
535         "movq 8(%0), %%mm1\n"
536         "add %2, %0\n"
537         "jmp 2f\n"
538         "1:\n"
539
540         SUM(%%mm4, %%mm5, %%mm0, %%mm1)
541         "2:\n"
542         SUM(%%mm0, %%mm1, %%mm4, %%mm5)
543
544         "subl $2, %%ecx\n"
545         "jnz 1b\n"
546
547         "movd %%mm6, %1\n"
548         : "+r" (pix), "=r" (tmp)
549         : "r" ((x86_reg) line_size), "m" (h)
550         : "%ecx");
551
552     return tmp;
553 }
554 #undef SUM
555
556 static int vsad16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
557                       int line_size, int h)
558 {
559     int tmp;
560
561     av_assert2((((int) pix1) & 7) == 0);
562     av_assert2((((int) pix2) & 7) == 0);
563     av_assert2((line_size & 7) == 0);
564
565 #define SUM(in0, in1, out0, out1)       \
566     "movq (%0), %%mm2\n"                \
567     "movq (%1), " #out0 "\n"            \
568     "movq 8(%0), %%mm3\n"               \
569     "movq 8(%1), " #out1 "\n"           \
570     "add %3, %0\n"                      \
571     "add %3, %1\n"                      \
572     "psubb " #out0 ", %%mm2\n"          \
573     "psubb " #out1 ", %%mm3\n"          \
574     "pxor %%mm7, %%mm2\n"               \
575     "pxor %%mm7, %%mm3\n"               \
576     "movq %%mm2, " #out0 "\n"           \
577     "movq %%mm3, " #out1 "\n"           \
578     "psubusb " #in0 ", %%mm2\n"         \
579     "psubusb " #in1 ", %%mm3\n"         \
580     "psubusb " #out0 ", " #in0 "\n"     \
581     "psubusb " #out1 ", " #in1 "\n"     \
582     "por %%mm2, " #in0 "\n"             \
583     "por %%mm3, " #in1 "\n"             \
584     "movq " #in0 ", %%mm2\n"            \
585     "movq " #in1 ", %%mm3\n"            \
586     "punpcklbw %%mm7, " #in0 "\n"       \
587     "punpcklbw %%mm7, " #in1 "\n"       \
588     "punpckhbw %%mm7, %%mm2\n"          \
589     "punpckhbw %%mm7, %%mm3\n"          \
590     "paddw " #in1 ", " #in0 "\n"        \
591     "paddw %%mm3, %%mm2\n"              \
592     "paddw %%mm2, " #in0 "\n"           \
593     "paddw " #in0 ", %%mm6\n"
594
595
596     __asm__ volatile (
597         "movl %4, %%ecx\n"
598         "pxor %%mm6, %%mm6\n"
599         "pcmpeqw %%mm7, %%mm7\n"
600         "psllw $15, %%mm7\n"
601         "packsswb %%mm7, %%mm7\n"
602         "movq (%0), %%mm0\n"
603         "movq (%1), %%mm2\n"
604         "movq 8(%0), %%mm1\n"
605         "movq 8(%1), %%mm3\n"
606         "add %3, %0\n"
607         "add %3, %1\n"
608         "psubb %%mm2, %%mm0\n"
609         "psubb %%mm3, %%mm1\n"
610         "pxor %%mm7, %%mm0\n"
611         "pxor %%mm7, %%mm1\n"
612         "jmp 2f\n"
613         "1:\n"
614
615         SUM(%%mm4, %%mm5, %%mm0, %%mm1)
616         "2:\n"
617         SUM(%%mm0, %%mm1, %%mm4, %%mm5)
618
619         "subl $2, %%ecx\n"
620         "jnz 1b\n"
621
622         "movq %%mm6, %%mm0\n"
623         "psrlq $32, %%mm6\n"
624         "paddw %%mm6, %%mm0\n"
625         "movq %%mm0, %%mm6\n"
626         "psrlq $16, %%mm0\n"
627         "paddw %%mm6, %%mm0\n"
628         "movd %%mm0, %2\n"
629         : "+r" (pix1), "+r" (pix2), "=r" (tmp)
630         : "r" ((x86_reg) line_size), "m" (h)
631         : "%ecx");
632
633     return tmp & 0x7FFF;
634 }
635 #undef SUM
636
637 static int vsad16_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
638                          int line_size, int h)
639 {
640     int tmp;
641
642     av_assert2((((int) pix1) & 7) == 0);
643     av_assert2((((int) pix2) & 7) == 0);
644     av_assert2((line_size & 7) == 0);
645
646 #define SUM(in0, in1, out0, out1)               \
647     "movq (%0), " #out0 "\n"                    \
648     "movq (%1), %%mm2\n"                        \
649     "movq 8(%0), " #out1 "\n"                   \
650     "movq 8(%1), %%mm3\n"                       \
651     "add %3, %0\n"                              \
652     "add %3, %1\n"                              \
653     "psubb %%mm2, " #out0 "\n"                  \
654     "psubb %%mm3, " #out1 "\n"                  \
655     "pxor %%mm7, " #out0 "\n"                   \
656     "pxor %%mm7, " #out1 "\n"                   \
657     "psadbw " #out0 ", " #in0 "\n"              \
658     "psadbw " #out1 ", " #in1 "\n"              \
659     "paddw " #in1 ", " #in0 "\n"                \
660     "paddw " #in0 ", %%mm6\n    "
661
662     __asm__ volatile (
663         "movl %4, %%ecx\n"
664         "pxor %%mm6, %%mm6\n"
665         "pcmpeqw %%mm7, %%mm7\n"
666         "psllw $15, %%mm7\n"
667         "packsswb %%mm7, %%mm7\n"
668         "movq (%0), %%mm0\n"
669         "movq (%1), %%mm2\n"
670         "movq 8(%0), %%mm1\n"
671         "movq 8(%1), %%mm3\n"
672         "add %3, %0\n"
673         "add %3, %1\n"
674         "psubb %%mm2, %%mm0\n"
675         "psubb %%mm3, %%mm1\n"
676         "pxor %%mm7, %%mm0\n"
677         "pxor %%mm7, %%mm1\n"
678         "jmp 2f\n"
679         "1:\n"
680
681         SUM(%%mm4, %%mm5, %%mm0, %%mm1)
682         "2:\n"
683         SUM(%%mm0, %%mm1, %%mm4, %%mm5)
684
685         "subl $2, %%ecx\n"
686         "jnz 1b\n"
687
688         "movd %%mm6, %2\n"
689         : "+r" (pix1), "+r" (pix2), "=r" (tmp)
690         : "r" ((x86_reg) line_size), "m" (h)
691         : "%ecx");
692
693     return tmp;
694 }
695 #undef SUM
696
697 static void diff_bytes_mmx(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, int w)
698 {
699     x86_reg i = 0;
700
701     if (w >= 16)
702     __asm__ volatile (
703         "1:                             \n\t"
704         "movq  (%2, %0), %%mm0          \n\t"
705         "movq  (%1, %0), %%mm1          \n\t"
706         "psubb %%mm0, %%mm1             \n\t"
707         "movq %%mm1, (%3, %0)           \n\t"
708         "movq 8(%2, %0), %%mm0          \n\t"
709         "movq 8(%1, %0), %%mm1          \n\t"
710         "psubb %%mm0, %%mm1             \n\t"
711         "movq %%mm1, 8(%3, %0)          \n\t"
712         "add $16, %0                    \n\t"
713         "cmp %4, %0                     \n\t"
714         " jb 1b                         \n\t"
715         : "+r" (i)
716         : "r" (src1), "r" (src2), "r" (dst), "r" ((x86_reg) w - 15));
717
718     for (; i < w; i++)
719         dst[i + 0] = src1[i + 0] - src2[i + 0];
720 }
721
722 static void sub_hfyu_median_prediction_mmxext(uint8_t *dst, const uint8_t *src1,
723                                               const uint8_t *src2, int w,
724                                               int *left, int *left_top)
725 {
726     x86_reg i = 0;
727     uint8_t l, lt;
728
729     __asm__ volatile (
730         "movq  (%1, %0), %%mm0          \n\t" // LT
731         "psllq $8, %%mm0                \n\t"
732         "1:                             \n\t"
733         "movq  (%1, %0), %%mm1          \n\t" // T
734         "movq  -1(%2, %0), %%mm2        \n\t" // L
735         "movq  (%2, %0), %%mm3          \n\t" // X
736         "movq %%mm2, %%mm4              \n\t" // L
737         "psubb %%mm0, %%mm2             \n\t"
738         "paddb %%mm1, %%mm2             \n\t" // L + T - LT
739         "movq %%mm4, %%mm5              \n\t" // L
740         "pmaxub %%mm1, %%mm4            \n\t" // max(T, L)
741         "pminub %%mm5, %%mm1            \n\t" // min(T, L)
742         "pminub %%mm2, %%mm4            \n\t"
743         "pmaxub %%mm1, %%mm4            \n\t"
744         "psubb %%mm4, %%mm3             \n\t" // dst - pred
745         "movq %%mm3, (%3, %0)           \n\t"
746         "add $8, %0                     \n\t"
747         "movq -1(%1, %0), %%mm0         \n\t" // LT
748         "cmp %4, %0                     \n\t"
749         " jb 1b                         \n\t"
750         : "+r" (i)
751         : "r" (src1), "r" (src2), "r" (dst), "r" ((x86_reg) w));
752
753     l  = *left;
754     lt = *left_top;
755
756     dst[0] = src2[0] - mid_pred(l, src1[0], (l + src1[0] - lt) & 0xFF);
757
758     *left_top = src1[w - 1];
759     *left     = src2[w - 1];
760 }
761
762 #define MMABS_MMX(a,z)                          \
763     "pxor "    #z ", " #z "             \n\t"   \
764     "pcmpgtw " #a ", " #z "             \n\t"   \
765     "pxor "    #z ", " #a "             \n\t"   \
766     "psubw "   #z ", " #a "             \n\t"
767
768 #define MMABS_MMXEXT(a, z)                      \
769     "pxor "    #z ", " #z "             \n\t"   \
770     "psubw "   #a ", " #z "             \n\t"   \
771     "pmaxsw "  #z ", " #a "             \n\t"
772
773 #define MMABS_SSSE3(a,z)                        \
774     "pabsw "   #a ", " #a "             \n\t"
775
776 #define MMABS_SUM(a,z, sum)                     \
777     MMABS(a,z)                                  \
778     "paddusw " #a ", " #sum "           \n\t"
779
780 /* FIXME: HSUM_* saturates at 64k, while an 8x8 hadamard or dct block can get
781  * up to about 100k on extreme inputs. But that's very unlikely to occur in
782  * natural video, and it's even more unlikely to not have any alternative
783  * mvs/modes with lower cost. */
784 #define HSUM_MMX(a, t, dst)                     \
785     "movq    " #a ", " #t "             \n\t"   \
786     "psrlq      $32, " #a "             \n\t"   \
787     "paddusw " #t ", " #a "             \n\t"   \
788     "movq    " #a ", " #t "             \n\t"   \
789     "psrlq      $16, " #a "             \n\t"   \
790     "paddusw " #t ", " #a "             \n\t"   \
791     "movd    " #a ", " #dst "           \n\t"   \
792
793 #define HSUM_MMXEXT(a, t, dst)                  \
794     "pshufw   $0x0E, " #a ", " #t "     \n\t"   \
795     "paddusw " #t ", " #a "             \n\t"   \
796     "pshufw   $0x01, " #a ", " #t "     \n\t"   \
797     "paddusw " #t ", " #a "             \n\t"   \
798     "movd    " #a ", " #dst "           \n\t"   \
799
800 #define HSUM_SSE2(a, t, dst)                    \
801     "movhlps " #a ", " #t "             \n\t"   \
802     "paddusw " #t ", " #a "             \n\t"   \
803     "pshuflw  $0x0E, " #a ", " #t "     \n\t"   \
804     "paddusw " #t ", " #a "             \n\t"   \
805     "pshuflw  $0x01, " #a ", " #t "     \n\t"   \
806     "paddusw " #t ", " #a "             \n\t"   \
807     "movd    " #a ", " #dst "           \n\t"   \
808
809 #define DCT_SAD4(m, mm, o)                      \
810     "mov"#m" "#o" +  0(%1), " #mm "2    \n\t"   \
811     "mov"#m" "#o" + 16(%1), " #mm "3    \n\t"   \
812     "mov"#m" "#o" + 32(%1), " #mm "4    \n\t"   \
813     "mov"#m" "#o" + 48(%1), " #mm "5    \n\t"   \
814     MMABS_SUM(mm ## 2, mm ## 6, mm ## 0)        \
815     MMABS_SUM(mm ## 3, mm ## 7, mm ## 1)        \
816     MMABS_SUM(mm ## 4, mm ## 6, mm ## 0)        \
817     MMABS_SUM(mm ## 5, mm ## 7, mm ## 1)        \
818
819 #define DCT_SAD_MMX                             \
820     "pxor    %%mm0, %%mm0               \n\t"   \
821     "pxor    %%mm1, %%mm1               \n\t"   \
822     DCT_SAD4(q, %%mm, 0)                        \
823     DCT_SAD4(q, %%mm, 8)                        \
824     DCT_SAD4(q, %%mm, 64)                       \
825     DCT_SAD4(q, %%mm, 72)                       \
826     "paddusw %%mm1, %%mm0               \n\t"   \
827     HSUM(%%mm0, %%mm1, %0)
828
829 #define DCT_SAD_SSE2                            \
830     "pxor    %%xmm0, %%xmm0             \n\t"   \
831     "pxor    %%xmm1, %%xmm1             \n\t"   \
832     DCT_SAD4(dqa, %%xmm, 0)                     \
833     DCT_SAD4(dqa, %%xmm, 64)                    \
834     "paddusw %%xmm1, %%xmm0             \n\t"   \
835     HSUM(%%xmm0, %%xmm1, %0)
836
837 #define DCT_SAD_FUNC(cpu)                           \
838 static int sum_abs_dctelem_ ## cpu(int16_t *block)  \
839 {                                                   \
840     int sum;                                        \
841     __asm__ volatile (                              \
842         DCT_SAD                                     \
843         :"=r"(sum)                                  \
844         :"r"(block));                               \
845     return sum & 0xFFFF;                            \
846 }
847
848 #define DCT_SAD         DCT_SAD_MMX
849 #define HSUM(a, t, dst) HSUM_MMX(a, t, dst)
850 #define MMABS(a, z)     MMABS_MMX(a, z)
851 DCT_SAD_FUNC(mmx)
852 #undef MMABS
853 #undef HSUM
854
855 #define HSUM(a, t, dst) HSUM_MMXEXT(a, t, dst)
856 #define MMABS(a, z)     MMABS_MMXEXT(a, z)
857 DCT_SAD_FUNC(mmxext)
858 #undef HSUM
859 #undef DCT_SAD
860
861 #define DCT_SAD         DCT_SAD_SSE2
862 #define HSUM(a, t, dst) HSUM_SSE2(a, t, dst)
863 DCT_SAD_FUNC(sse2)
864 #undef MMABS
865
866 #if HAVE_SSSE3_INLINE
867 #define MMABS(a, z)     MMABS_SSSE3(a, z)
868 DCT_SAD_FUNC(ssse3)
869 #undef MMABS
870 #endif
871 #undef HSUM
872 #undef DCT_SAD
873
874 static int ssd_int8_vs_int16_mmx(const int8_t *pix1, const int16_t *pix2,
875                                  int size)
876 {
877     int sum;
878     x86_reg i = size;
879
880     __asm__ volatile (
881         "pxor %%mm4, %%mm4 \n"
882         "1: \n"
883         "sub $8, %0 \n"
884         "movq (%2, %0), %%mm2 \n"
885         "movq (%3, %0, 2), %%mm0 \n"
886         "movq 8(%3, %0, 2), %%mm1 \n"
887         "punpckhbw %%mm2, %%mm3 \n"
888         "punpcklbw %%mm2, %%mm2 \n"
889         "psraw $8, %%mm3 \n"
890         "psraw $8, %%mm2 \n"
891         "psubw %%mm3, %%mm1 \n"
892         "psubw %%mm2, %%mm0 \n"
893         "pmaddwd %%mm1, %%mm1 \n"
894         "pmaddwd %%mm0, %%mm0 \n"
895         "paddd %%mm1, %%mm4 \n"
896         "paddd %%mm0, %%mm4 \n"
897         "jg 1b \n"
898         "movq %%mm4, %%mm3 \n"
899         "psrlq $32, %%mm3 \n"
900         "paddd %%mm3, %%mm4 \n"
901         "movd %%mm4, %1 \n"
902         : "+r" (i), "=r" (sum)
903         : "r" (pix1), "r" (pix2));
904
905     return sum;
906 }
907
908 #define PHADDD(a, t)                            \
909     "movq  " #a ", " #t "               \n\t"   \
910     "psrlq    $32, " #a "               \n\t"   \
911     "paddd " #t ", " #a "               \n\t"
912
913 /*
914  * pmulhw:   dst[0 - 15] = (src[0 - 15] * dst[0 - 15])[16 - 31]
915  * pmulhrw:  dst[0 - 15] = (src[0 - 15] * dst[0 - 15] + 0x8000)[16 - 31]
916  * pmulhrsw: dst[0 - 15] = (src[0 - 15] * dst[0 - 15] + 0x4000)[15 - 30]
917  */
918 #define PMULHRW(x, y, s, o)                     \
919     "pmulhw " #s ", " #x "              \n\t"   \
920     "pmulhw " #s ", " #y "              \n\t"   \
921     "paddw  " #o ", " #x "              \n\t"   \
922     "paddw  " #o ", " #y "              \n\t"   \
923     "psraw      $1, " #x "              \n\t"   \
924     "psraw      $1, " #y "              \n\t"
925 #define DEF(x) x ## _mmx
926 #define SET_RND MOVQ_WONE
927 #define SCALE_OFFSET 1
928
929 #include "dsputil_qns_template.c"
930
931 #undef DEF
932 #undef SET_RND
933 #undef SCALE_OFFSET
934 #undef PMULHRW
935
936 #define DEF(x) x ## _3dnow
937 #define SET_RND(x)
938 #define SCALE_OFFSET 0
939 #define PMULHRW(x, y, s, o)                     \
940     "pmulhrw " #s ", " #x "             \n\t"   \
941     "pmulhrw " #s ", " #y "             \n\t"
942
943 #include "dsputil_qns_template.c"
944
945 #undef DEF
946 #undef SET_RND
947 #undef SCALE_OFFSET
948 #undef PMULHRW
949
950 #if HAVE_SSSE3_INLINE
951 #undef PHADDD
952 #define DEF(x) x ## _ssse3
953 #define SET_RND(x)
954 #define SCALE_OFFSET -1
955
956 #define PHADDD(a, t)                            \
957     "pshufw $0x0E, " #a ", " #t "       \n\t"   \
958     /* faster than phaddd on core2 */           \
959     "paddd " #t ", " #a "               \n\t"
960
961 #define PMULHRW(x, y, s, o)                     \
962     "pmulhrsw " #s ", " #x "            \n\t"   \
963     "pmulhrsw " #s ", " #y "            \n\t"
964
965 #include "dsputil_qns_template.c"
966
967 #undef DEF
968 #undef SET_RND
969 #undef SCALE_OFFSET
970 #undef PMULHRW
971 #undef PHADDD
972 #endif /* HAVE_SSSE3_INLINE */
973
974 #endif /* HAVE_INLINE_ASM */
975
976 int ff_sse16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
977                   int line_size, int h);
978
979 #define hadamard_func(cpu)                                              \
980     int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, uint8_t *src1,     \
981                                   uint8_t *src2, int stride, int h);    \
982     int ff_hadamard8_diff16_ ## cpu(MpegEncContext *s, uint8_t *src1,   \
983                                     uint8_t *src2, int stride, int h);
984
985 hadamard_func(mmx)
986 hadamard_func(mmxext)
987 hadamard_func(sse2)
988 hadamard_func(ssse3)
989
990 av_cold void ff_dsputilenc_init_mmx(DSPContext *c, AVCodecContext *avctx,
991                                     unsigned high_bit_depth)
992 {
993     int cpu_flags = av_get_cpu_flags();
994     const int dct_algo = avctx->dct_algo;
995
996     if (EXTERNAL_MMX(cpu_flags)) {
997         if (!high_bit_depth)
998             c->get_pixels = ff_get_pixels_mmx;
999         c->diff_pixels = ff_diff_pixels_mmx;
1000         c->pix_sum     = ff_pix_sum16_mmx;
1001         c->pix_norm1   = ff_pix_norm1_mmx;
1002     }
1003
1004     if (EXTERNAL_SSE2(cpu_flags))
1005         if (!high_bit_depth)
1006             c->get_pixels = ff_get_pixels_sse2;
1007
1008 #if HAVE_INLINE_ASM
1009     if (INLINE_MMX(cpu_flags)) {
1010         if (!high_bit_depth &&
1011             (dct_algo == FF_DCT_AUTO || dct_algo == FF_DCT_MMX))
1012             c->fdct = ff_fdct_mmx;
1013
1014         c->diff_bytes      = diff_bytes_mmx;
1015         c->sum_abs_dctelem = sum_abs_dctelem_mmx;
1016
1017         c->sse[0]  = sse16_mmx;
1018         c->sse[1]  = sse8_mmx;
1019         c->vsad[4] = vsad_intra16_mmx;
1020
1021         c->nsse[0] = nsse16_mmx;
1022         c->nsse[1] = nsse8_mmx;
1023         if (!(avctx->flags & CODEC_FLAG_BITEXACT)) {
1024             c->vsad[0]      = vsad16_mmx;
1025             c->try_8x8basis = try_8x8basis_mmx;
1026         }
1027         c->add_8x8basis = add_8x8basis_mmx;
1028
1029         c->ssd_int8_vs_int16 = ssd_int8_vs_int16_mmx;
1030     }
1031
1032     if (INLINE_AMD3DNOW(cpu_flags)) {
1033         if (!(avctx->flags & CODEC_FLAG_BITEXACT)) {
1034             c->try_8x8basis = try_8x8basis_3dnow;
1035         }
1036         c->add_8x8basis = add_8x8basis_3dnow;
1037     }
1038
1039     if (INLINE_MMXEXT(cpu_flags)) {
1040         if (!high_bit_depth &&
1041             (dct_algo == FF_DCT_AUTO || dct_algo == FF_DCT_MMX))
1042             c->fdct = ff_fdct_mmxext;
1043
1044         c->sum_abs_dctelem = sum_abs_dctelem_mmxext;
1045         c->vsad[4]         = vsad_intra16_mmxext;
1046
1047         if (!(avctx->flags & CODEC_FLAG_BITEXACT)) {
1048             c->vsad[0] = vsad16_mmxext;
1049         }
1050
1051         c->sub_hfyu_median_prediction = sub_hfyu_median_prediction_mmxext;
1052     }
1053
1054     if (INLINE_SSE2(cpu_flags)) {
1055         if (!high_bit_depth &&
1056             (dct_algo == FF_DCT_AUTO || dct_algo == FF_DCT_MMX))
1057             c->fdct = ff_fdct_sse2;
1058
1059         c->sum_abs_dctelem = sum_abs_dctelem_sse2;
1060     }
1061
1062 #if HAVE_SSSE3_INLINE
1063     if (INLINE_SSSE3(cpu_flags)) {
1064         if (!(avctx->flags & CODEC_FLAG_BITEXACT)) {
1065             c->try_8x8basis = try_8x8basis_ssse3;
1066         }
1067         c->add_8x8basis    = add_8x8basis_ssse3;
1068         c->sum_abs_dctelem = sum_abs_dctelem_ssse3;
1069     }
1070 #endif
1071 #endif /* HAVE_INLINE_ASM */
1072
1073     if (EXTERNAL_MMX(cpu_flags)) {
1074         c->hadamard8_diff[0] = ff_hadamard8_diff16_mmx;
1075         c->hadamard8_diff[1] = ff_hadamard8_diff_mmx;
1076     }
1077
1078     if (EXTERNAL_MMXEXT(cpu_flags)) {
1079         c->hadamard8_diff[0] = ff_hadamard8_diff16_mmxext;
1080         c->hadamard8_diff[1] = ff_hadamard8_diff_mmxext;
1081     }
1082
1083     if (EXTERNAL_SSE2(cpu_flags)) {
1084         c->sse[0] = ff_sse16_sse2;
1085
1086 #if HAVE_ALIGNED_STACK
1087         c->hadamard8_diff[0] = ff_hadamard8_diff16_sse2;
1088         c->hadamard8_diff[1] = ff_hadamard8_diff_sse2;
1089 #endif
1090     }
1091
1092     if (EXTERNAL_SSSE3(cpu_flags) && HAVE_ALIGNED_STACK) {
1093         c->hadamard8_diff[0] = ff_hadamard8_diff16_ssse3;
1094         c->hadamard8_diff[1] = ff_hadamard8_diff_ssse3;
1095     }
1096
1097     ff_dsputil_init_pix_mmx(c, avctx);
1098 }