Consistently use "cpu_flags" as variable/parameter name for CPU flags
[ffmpeg.git] / libavcodec / x86 / motion_est.c
1 /*
2  * MMX optimized motion estimation
3  * Copyright (c) 2001 Fabrice Bellard
4  * Copyright (c) 2002-2004 Michael Niedermayer
5  *
6  * mostly by Michael Niedermayer <michaelni@gmx.at>
7  *
8  * This file is part of Libav.
9  *
10  * Libav 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  * Libav 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 Libav; 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/internal.h"
27 #include "libavutil/mem.h"
28 #include "libavutil/x86/asm.h"
29 #include "dsputil_x86.h"
30
31 #if HAVE_INLINE_ASM
32
33 DECLARE_ASM_CONST(8, uint64_t, round_tab)[3]={
34 0x0000000000000000ULL,
35 0x0001000100010001ULL,
36 0x0002000200020002ULL,
37 };
38
39 DECLARE_ASM_CONST(8, uint64_t, bone)= 0x0101010101010101LL;
40
41 static inline void sad8_1_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
42 {
43     x86_reg len= -(stride*h);
44     __asm__ volatile(
45         ".p2align 4                     \n\t"
46         "1:                             \n\t"
47         "movq (%1, %%"REG_a"), %%mm0    \n\t"
48         "movq (%2, %%"REG_a"), %%mm2    \n\t"
49         "movq (%2, %%"REG_a"), %%mm4    \n\t"
50         "add %3, %%"REG_a"              \n\t"
51         "psubusb %%mm0, %%mm2           \n\t"
52         "psubusb %%mm4, %%mm0           \n\t"
53         "movq (%1, %%"REG_a"), %%mm1    \n\t"
54         "movq (%2, %%"REG_a"), %%mm3    \n\t"
55         "movq (%2, %%"REG_a"), %%mm5    \n\t"
56         "psubusb %%mm1, %%mm3           \n\t"
57         "psubusb %%mm5, %%mm1           \n\t"
58         "por %%mm2, %%mm0               \n\t"
59         "por %%mm1, %%mm3               \n\t"
60         "movq %%mm0, %%mm1              \n\t"
61         "movq %%mm3, %%mm2              \n\t"
62         "punpcklbw %%mm7, %%mm0         \n\t"
63         "punpckhbw %%mm7, %%mm1         \n\t"
64         "punpcklbw %%mm7, %%mm3         \n\t"
65         "punpckhbw %%mm7, %%mm2         \n\t"
66         "paddw %%mm1, %%mm0             \n\t"
67         "paddw %%mm3, %%mm2             \n\t"
68         "paddw %%mm2, %%mm0             \n\t"
69         "paddw %%mm0, %%mm6             \n\t"
70         "add %3, %%"REG_a"              \n\t"
71         " js 1b                         \n\t"
72         : "+a" (len)
73         : "r" (blk1 - len), "r" (blk2 - len), "r" ((x86_reg)stride)
74     );
75 }
76
77 static inline void sad8_1_mmxext(uint8_t *blk1, uint8_t *blk2,
78                                  int stride, int h)
79 {
80     __asm__ volatile(
81         ".p2align 4                     \n\t"
82         "1:                             \n\t"
83         "movq (%1), %%mm0               \n\t"
84         "movq (%1, %3), %%mm1           \n\t"
85         "psadbw (%2), %%mm0             \n\t"
86         "psadbw (%2, %3), %%mm1         \n\t"
87         "paddw %%mm0, %%mm6             \n\t"
88         "paddw %%mm1, %%mm6             \n\t"
89         "lea (%1,%3,2), %1              \n\t"
90         "lea (%2,%3,2), %2              \n\t"
91         "sub $2, %0                     \n\t"
92         " jg 1b                         \n\t"
93         : "+r" (h), "+r" (blk1), "+r" (blk2)
94         : "r" ((x86_reg)stride)
95     );
96 }
97
98 static int sad16_sse2(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)
99 {
100     int ret;
101     __asm__ volatile(
102         "pxor %%xmm2, %%xmm2            \n\t"
103         ".p2align 4                     \n\t"
104         "1:                             \n\t"
105         "movdqu (%1), %%xmm0            \n\t"
106         "movdqu (%1, %4), %%xmm1        \n\t"
107         "psadbw (%2), %%xmm0            \n\t"
108         "psadbw (%2, %4), %%xmm1        \n\t"
109         "paddw %%xmm0, %%xmm2           \n\t"
110         "paddw %%xmm1, %%xmm2           \n\t"
111         "lea (%1,%4,2), %1              \n\t"
112         "lea (%2,%4,2), %2              \n\t"
113         "sub $2, %0                     \n\t"
114         " jg 1b                         \n\t"
115         "movhlps %%xmm2, %%xmm0         \n\t"
116         "paddw   %%xmm0, %%xmm2         \n\t"
117         "movd    %%xmm2, %3             \n\t"
118         : "+r" (h), "+r" (blk1), "+r" (blk2), "=r"(ret)
119         : "r" ((x86_reg)stride)
120     );
121     return ret;
122 }
123
124 static inline void sad8_x2a_mmxext(uint8_t *blk1, uint8_t *blk2,
125                                    int stride, int h)
126 {
127     __asm__ volatile(
128         ".p2align 4                     \n\t"
129         "1:                             \n\t"
130         "movq (%1), %%mm0               \n\t"
131         "movq (%1, %3), %%mm1           \n\t"
132         "pavgb 1(%1), %%mm0             \n\t"
133         "pavgb 1(%1, %3), %%mm1         \n\t"
134         "psadbw (%2), %%mm0             \n\t"
135         "psadbw (%2, %3), %%mm1         \n\t"
136         "paddw %%mm0, %%mm6             \n\t"
137         "paddw %%mm1, %%mm6             \n\t"
138         "lea (%1,%3,2), %1              \n\t"
139         "lea (%2,%3,2), %2              \n\t"
140         "sub $2, %0                     \n\t"
141         " jg 1b                         \n\t"
142         : "+r" (h), "+r" (blk1), "+r" (blk2)
143         : "r" ((x86_reg)stride)
144     );
145 }
146
147 static inline void sad8_y2a_mmxext(uint8_t *blk1, uint8_t *blk2,
148                                    int stride, int h)
149 {
150     __asm__ volatile(
151         "movq (%1), %%mm0               \n\t"
152         "add %3, %1                     \n\t"
153         ".p2align 4                     \n\t"
154         "1:                             \n\t"
155         "movq (%1), %%mm1               \n\t"
156         "movq (%1, %3), %%mm2           \n\t"
157         "pavgb %%mm1, %%mm0             \n\t"
158         "pavgb %%mm2, %%mm1             \n\t"
159         "psadbw (%2), %%mm0             \n\t"
160         "psadbw (%2, %3), %%mm1         \n\t"
161         "paddw %%mm0, %%mm6             \n\t"
162         "paddw %%mm1, %%mm6             \n\t"
163         "movq %%mm2, %%mm0              \n\t"
164         "lea (%1,%3,2), %1              \n\t"
165         "lea (%2,%3,2), %2              \n\t"
166         "sub $2, %0                     \n\t"
167         " jg 1b                         \n\t"
168         : "+r" (h), "+r" (blk1), "+r" (blk2)
169         : "r" ((x86_reg)stride)
170     );
171 }
172
173 static inline void sad8_4_mmxext(uint8_t *blk1, uint8_t *blk2,
174                                  int stride, int h)
175 {
176     __asm__ volatile(
177         "movq "MANGLE(bone)", %%mm5     \n\t"
178         "movq (%1), %%mm0               \n\t"
179         "pavgb 1(%1), %%mm0             \n\t"
180         "add %3, %1                     \n\t"
181         ".p2align 4                     \n\t"
182         "1:                             \n\t"
183         "movq (%1), %%mm1               \n\t"
184         "movq (%1,%3), %%mm2            \n\t"
185         "pavgb 1(%1), %%mm1             \n\t"
186         "pavgb 1(%1,%3), %%mm2          \n\t"
187         "psubusb %%mm5, %%mm1           \n\t"
188         "pavgb %%mm1, %%mm0             \n\t"
189         "pavgb %%mm2, %%mm1             \n\t"
190         "psadbw (%2), %%mm0             \n\t"
191         "psadbw (%2,%3), %%mm1          \n\t"
192         "paddw %%mm0, %%mm6             \n\t"
193         "paddw %%mm1, %%mm6             \n\t"
194         "movq %%mm2, %%mm0              \n\t"
195         "lea (%1,%3,2), %1              \n\t"
196         "lea (%2,%3,2), %2              \n\t"
197         "sub $2, %0                     \n\t"
198         " jg 1b                         \n\t"
199         : "+r" (h), "+r" (blk1), "+r" (blk2)
200         : "r" ((x86_reg)stride)
201     );
202 }
203
204 static inline void sad8_2_mmx(uint8_t *blk1a, uint8_t *blk1b, uint8_t *blk2, int stride, int h)
205 {
206     x86_reg len= -(stride*h);
207     __asm__ volatile(
208         ".p2align 4                     \n\t"
209         "1:                             \n\t"
210         "movq (%1, %%"REG_a"), %%mm0    \n\t"
211         "movq (%2, %%"REG_a"), %%mm1    \n\t"
212         "movq (%1, %%"REG_a"), %%mm2    \n\t"
213         "movq (%2, %%"REG_a"), %%mm3    \n\t"
214         "punpcklbw %%mm7, %%mm0         \n\t"
215         "punpcklbw %%mm7, %%mm1         \n\t"
216         "punpckhbw %%mm7, %%mm2         \n\t"
217         "punpckhbw %%mm7, %%mm3         \n\t"
218         "paddw %%mm0, %%mm1             \n\t"
219         "paddw %%mm2, %%mm3             \n\t"
220         "movq (%3, %%"REG_a"), %%mm4    \n\t"
221         "movq (%3, %%"REG_a"), %%mm2    \n\t"
222         "paddw %%mm5, %%mm1             \n\t"
223         "paddw %%mm5, %%mm3             \n\t"
224         "psrlw $1, %%mm1                \n\t"
225         "psrlw $1, %%mm3                \n\t"
226         "packuswb %%mm3, %%mm1          \n\t"
227         "psubusb %%mm1, %%mm4           \n\t"
228         "psubusb %%mm2, %%mm1           \n\t"
229         "por %%mm4, %%mm1               \n\t"
230         "movq %%mm1, %%mm0              \n\t"
231         "punpcklbw %%mm7, %%mm0         \n\t"
232         "punpckhbw %%mm7, %%mm1         \n\t"
233         "paddw %%mm1, %%mm0             \n\t"
234         "paddw %%mm0, %%mm6             \n\t"
235         "add %4, %%"REG_a"              \n\t"
236         " js 1b                         \n\t"
237         : "+a" (len)
238         : "r" (blk1a - len), "r" (blk1b -len), "r" (blk2 - len), "r" ((x86_reg)stride)
239     );
240 }
241
242 static inline void sad8_4_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
243 {
244     x86_reg len= -(stride*h);
245     __asm__ volatile(
246         "movq (%1, %%"REG_a"), %%mm0    \n\t"
247         "movq 1(%1, %%"REG_a"), %%mm2   \n\t"
248         "movq %%mm0, %%mm1              \n\t"
249         "movq %%mm2, %%mm3              \n\t"
250         "punpcklbw %%mm7, %%mm0         \n\t"
251         "punpckhbw %%mm7, %%mm1         \n\t"
252         "punpcklbw %%mm7, %%mm2         \n\t"
253         "punpckhbw %%mm7, %%mm3         \n\t"
254         "paddw %%mm2, %%mm0             \n\t"
255         "paddw %%mm3, %%mm1             \n\t"
256         ".p2align 4                     \n\t"
257         "1:                             \n\t"
258         "movq (%2, %%"REG_a"), %%mm2    \n\t"
259         "movq 1(%2, %%"REG_a"), %%mm4   \n\t"
260         "movq %%mm2, %%mm3              \n\t"
261         "movq %%mm4, %%mm5              \n\t"
262         "punpcklbw %%mm7, %%mm2         \n\t"
263         "punpckhbw %%mm7, %%mm3         \n\t"
264         "punpcklbw %%mm7, %%mm4         \n\t"
265         "punpckhbw %%mm7, %%mm5         \n\t"
266         "paddw %%mm4, %%mm2             \n\t"
267         "paddw %%mm5, %%mm3             \n\t"
268         "movq 16+"MANGLE(round_tab)", %%mm5 \n\t"
269         "paddw %%mm2, %%mm0             \n\t"
270         "paddw %%mm3, %%mm1             \n\t"
271         "paddw %%mm5, %%mm0             \n\t"
272         "paddw %%mm5, %%mm1             \n\t"
273         "movq (%3, %%"REG_a"), %%mm4    \n\t"
274         "movq (%3, %%"REG_a"), %%mm5    \n\t"
275         "psrlw $2, %%mm0                \n\t"
276         "psrlw $2, %%mm1                \n\t"
277         "packuswb %%mm1, %%mm0          \n\t"
278         "psubusb %%mm0, %%mm4           \n\t"
279         "psubusb %%mm5, %%mm0           \n\t"
280         "por %%mm4, %%mm0               \n\t"
281         "movq %%mm0, %%mm4              \n\t"
282         "punpcklbw %%mm7, %%mm0         \n\t"
283         "punpckhbw %%mm7, %%mm4         \n\t"
284         "paddw %%mm0, %%mm6             \n\t"
285         "paddw %%mm4, %%mm6             \n\t"
286         "movq  %%mm2, %%mm0             \n\t"
287         "movq  %%mm3, %%mm1             \n\t"
288         "add %4, %%"REG_a"              \n\t"
289         " js 1b                         \n\t"
290         : "+a" (len)
291         : "r" (blk1 - len), "r" (blk1 -len + stride), "r" (blk2 - len), "r" ((x86_reg)stride)
292     );
293 }
294
295 static inline int sum_mmx(void)
296 {
297     int ret;
298     __asm__ volatile(
299         "movq %%mm6, %%mm0              \n\t"
300         "psrlq $32, %%mm6               \n\t"
301         "paddw %%mm0, %%mm6             \n\t"
302         "movq %%mm6, %%mm0              \n\t"
303         "psrlq $16, %%mm6               \n\t"
304         "paddw %%mm0, %%mm6             \n\t"
305         "movd %%mm6, %0                 \n\t"
306         : "=r" (ret)
307     );
308     return ret&0xFFFF;
309 }
310
311 static inline int sum_mmxext(void)
312 {
313     int ret;
314     __asm__ volatile(
315         "movd %%mm6, %0                 \n\t"
316         : "=r" (ret)
317     );
318     return ret;
319 }
320
321 static inline void sad8_x2a_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
322 {
323     sad8_2_mmx(blk1, blk1+1, blk2, stride, h);
324 }
325 static inline void sad8_y2a_mmx(uint8_t *blk1, uint8_t *blk2, int stride, int h)
326 {
327     sad8_2_mmx(blk1, blk1+stride, blk2, stride, h);
328 }
329
330
331 #define PIX_SAD(suf)\
332 static int sad8_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
333 {\
334     assert(h==8);\
335     __asm__ volatile("pxor %%mm7, %%mm7     \n\t"\
336                  "pxor %%mm6, %%mm6     \n\t":);\
337 \
338     sad8_1_ ## suf(blk1, blk2, stride, 8);\
339 \
340     return sum_ ## suf();\
341 }\
342 static int sad8_x2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
343 {\
344     assert(h==8);\
345     __asm__ volatile("pxor %%mm7, %%mm7     \n\t"\
346                  "pxor %%mm6, %%mm6     \n\t"\
347                  "movq %0, %%mm5        \n\t"\
348                  :: "m"(round_tab[1]) \
349                  );\
350 \
351     sad8_x2a_ ## suf(blk1, blk2, stride, 8);\
352 \
353     return sum_ ## suf();\
354 }\
355 \
356 static int sad8_y2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
357 {\
358     assert(h==8);\
359     __asm__ volatile("pxor %%mm7, %%mm7     \n\t"\
360                  "pxor %%mm6, %%mm6     \n\t"\
361                  "movq %0, %%mm5        \n\t"\
362                  :: "m"(round_tab[1]) \
363                  );\
364 \
365     sad8_y2a_ ## suf(blk1, blk2, stride, 8);\
366 \
367     return sum_ ## suf();\
368 }\
369 \
370 static int sad8_xy2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
371 {\
372     assert(h==8);\
373     __asm__ volatile("pxor %%mm7, %%mm7     \n\t"\
374                  "pxor %%mm6, %%mm6     \n\t"\
375                  ::);\
376 \
377     sad8_4_ ## suf(blk1, blk2, stride, 8);\
378 \
379     return sum_ ## suf();\
380 }\
381 \
382 static int sad16_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
383 {\
384     __asm__ volatile("pxor %%mm7, %%mm7     \n\t"\
385                  "pxor %%mm6, %%mm6     \n\t":);\
386 \
387     sad8_1_ ## suf(blk1  , blk2  , stride, h);\
388     sad8_1_ ## suf(blk1+8, blk2+8, stride, h);\
389 \
390     return sum_ ## suf();\
391 }\
392 static int sad16_x2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
393 {\
394     __asm__ volatile("pxor %%mm7, %%mm7     \n\t"\
395                  "pxor %%mm6, %%mm6     \n\t"\
396                  "movq %0, %%mm5        \n\t"\
397                  :: "m"(round_tab[1]) \
398                  );\
399 \
400     sad8_x2a_ ## suf(blk1  , blk2  , stride, h);\
401     sad8_x2a_ ## suf(blk1+8, blk2+8, stride, h);\
402 \
403     return sum_ ## suf();\
404 }\
405 static int sad16_y2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
406 {\
407     __asm__ volatile("pxor %%mm7, %%mm7     \n\t"\
408                  "pxor %%mm6, %%mm6     \n\t"\
409                  "movq %0, %%mm5        \n\t"\
410                  :: "m"(round_tab[1]) \
411                  );\
412 \
413     sad8_y2a_ ## suf(blk1  , blk2  , stride, h);\
414     sad8_y2a_ ## suf(blk1+8, blk2+8, stride, h);\
415 \
416     return sum_ ## suf();\
417 }\
418 static int sad16_xy2_ ## suf(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)\
419 {\
420     __asm__ volatile("pxor %%mm7, %%mm7     \n\t"\
421                  "pxor %%mm6, %%mm6     \n\t"\
422                  ::);\
423 \
424     sad8_4_ ## suf(blk1  , blk2  , stride, h);\
425     sad8_4_ ## suf(blk1+8, blk2+8, stride, h);\
426 \
427     return sum_ ## suf();\
428 }\
429
430 PIX_SAD(mmx)
431 PIX_SAD(mmxext)
432
433 #endif /* HAVE_INLINE_ASM */
434
435 av_cold void ff_dsputil_init_pix_mmx(DSPContext *c, AVCodecContext *avctx)
436 {
437 #if HAVE_INLINE_ASM
438     int cpu_flags = av_get_cpu_flags();
439
440     if (cpu_flags & AV_CPU_FLAG_MMX) {
441         c->pix_abs[0][0] = sad16_mmx;
442         c->pix_abs[0][1] = sad16_x2_mmx;
443         c->pix_abs[0][2] = sad16_y2_mmx;
444         c->pix_abs[0][3] = sad16_xy2_mmx;
445         c->pix_abs[1][0] = sad8_mmx;
446         c->pix_abs[1][1] = sad8_x2_mmx;
447         c->pix_abs[1][2] = sad8_y2_mmx;
448         c->pix_abs[1][3] = sad8_xy2_mmx;
449
450         c->sad[0]= sad16_mmx;
451         c->sad[1]= sad8_mmx;
452     }
453     if (cpu_flags & AV_CPU_FLAG_MMXEXT) {
454         c->pix_abs[0][0] = sad16_mmxext;
455         c->pix_abs[1][0] = sad8_mmxext;
456
457         c->sad[0]        = sad16_mmxext;
458         c->sad[1]        = sad8_mmxext;
459
460         if(!(avctx->flags & CODEC_FLAG_BITEXACT)){
461             c->pix_abs[0][1] = sad16_x2_mmxext;
462             c->pix_abs[0][2] = sad16_y2_mmxext;
463             c->pix_abs[0][3] = sad16_xy2_mmxext;
464             c->pix_abs[1][1] = sad8_x2_mmxext;
465             c->pix_abs[1][2] = sad8_y2_mmxext;
466             c->pix_abs[1][3] = sad8_xy2_mmxext;
467         }
468     }
469     if ((cpu_flags & AV_CPU_FLAG_SSE2) && !(cpu_flags & AV_CPU_FLAG_3DNOW)) {
470         c->sad[0]= sad16_sse2;
471     }
472 #endif /* HAVE_INLINE_ASM */
473 }