]> git.sesse.net Git - vlc/blob - modules/codec/mpeg_video/motion/motionmmx.c
* ./modules/*: moved plugins to the new tree. Yet untested builds include
[vlc] / modules / codec / mpeg_video / motion / motionmmx.c
1 /*****************************************************************************
2  * motionmmx.c : MMX motion compensation module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: motionmmx.c,v 1.1 2002/08/04 17:23:42 sam Exp $
6  *
7  * Authors: Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
8  *          Michel Lespinasse <walken@zoy.org>
9  *          Vladimir Chernyshov <greengrass@writeme.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <string.h>
31
32 #include <vlc/vlc.h>
33
34 #include "mmx.h"
35
36 /*****************************************************************************
37  * Local prototype.
38  *****************************************************************************/
39 static int Open ( vlc_object_t * );
40
41 /*****************************************************************************
42  * Module descriptor
43  *****************************************************************************/
44 vlc_module_begin();
45     set_description( _("MMX motion compensation module") );
46     set_capability( "motion compensation", 150 );
47     add_requirement( MMX );
48     add_shortcut( "mmx" );
49     set_callbacks( Open, NULL );
50 vlc_module_end();
51
52 /*****************************************************************************
53  * Motion compensation in MMX
54  *****************************************************************************/
55
56 // some rounding constants
57 mmx_t round1 = {0x0001000100010001LL};
58 mmx_t round4 = {0x0002000200020002LL};
59
60 /*
61  * This code should probably be compiled with loop unrolling
62  * (ie, -funroll-loops in gcc)becuase some of the loops
63  * use a small static number of iterations. This was written
64  * with the assumption the compiler knows best about when
65  * unrolling will help
66  */
67
68 static inline void mmx_zero_reg ()
69 {
70     // load 0 into mm0
71     pxor_r2r (mm0, mm0);
72 }
73
74 static inline void mmx_average_2_U8 (yuv_data_t * dest,
75                                      yuv_data_t * src1, yuv_data_t * src2)
76 {
77     //
78     // *dest = (*src1 + *src2 + 1)/ 2;
79     //
80     static mmx_t mask1 = {0x0101010101010101LL};
81     static mmx_t mask7f = {0x7f7f7f7f7f7f7f7fLL};
82
83     movq_m2r (*src1, mm1);        // load 8 src1 bytes
84     movq_r2r (mm1, mm2);
85     psrlq_i2r (1, mm1);
86     pand_m2r (mask7f, mm1);
87
88     movq_m2r (*src2, mm3);        // load 8 src2 bytes
89     por_r2r (mm3, mm2);
90     psrlq_i2r (1, mm3);
91     pand_m2r (mask7f, mm3);
92
93     paddb_r2r (mm1, mm3);
94     pand_m2r (mask1, mm2);
95     paddb_r2r (mm3, mm2);
96     movq_r2m (mm2, *dest);        // store result in dest
97 }
98
99 static inline void mmx_interp_average_2_U8 (yuv_data_t * dest,
100                                             yuv_data_t * src1, yuv_data_t * src2)
101 {
102     //
103     // *dest = (*dest + (*src1 + *src2 + 1)/ 2 + 1)/ 2;
104     //
105
106     movq_m2r (*dest, mm1);        // load 8 dest bytes
107     movq_r2r (mm1, mm2);        // copy 8 dest bytes
108
109     movq_m2r (*src1, mm3);        // load 8 src1 bytes
110     movq_r2r (mm3, mm4);        // copy 8 src1 bytes
111
112     movq_m2r (*src2, mm5);        // load 8 src2 bytes
113     movq_r2r (mm5, mm6);        // copy 8 src2 bytes
114
115     punpcklbw_r2r (mm0, mm1);        // unpack low dest bytes
116     punpckhbw_r2r (mm0, mm2);        // unpack high dest bytes
117
118     punpcklbw_r2r (mm0, mm3);        // unpack low src1 bytes
119     punpckhbw_r2r (mm0, mm4);        // unpack high src1 bytes
120
121     punpcklbw_r2r (mm0, mm5);        // unpack low src2 bytes
122     punpckhbw_r2r (mm0, mm6);        // unpack high src2 bytes
123
124     paddw_r2r (mm5, mm3);        // add lows
125     paddw_m2r (round1, mm3);
126     psraw_i2r (1, mm3);                // /2
127
128     paddw_r2r (mm6, mm4);        // add highs
129     paddw_m2r (round1, mm4);
130     psraw_i2r (1, mm4);                // /2
131
132     paddw_r2r (mm3, mm1);        // add lows
133     paddw_m2r (round1, mm1);
134     psraw_i2r (1, mm1);                // /2
135
136     paddw_r2r (mm4, mm2);        // add highs
137     paddw_m2r (round1, mm2);
138     psraw_i2r (1, mm2);                // /2
139
140     packuswb_r2r (mm2, mm1);        // pack (w/ saturation)
141     movq_r2m (mm1, *dest);        // store result in dest
142 }
143
144 static inline void mmx_average_4_U8 (yuv_data_t * dest,
145                                      yuv_data_t * src1, yuv_data_t * src2,
146                                      yuv_data_t * src3, yuv_data_t * src4)
147 {
148     //
149     // *dest = (*src1 + *src2 + *src3 + *src4 + 2)/ 4;
150     //
151
152     movq_m2r (*src1, mm1);        // load 8 src1 bytes
153     movq_r2r (mm1, mm2);        // copy 8 src1 bytes
154
155     punpcklbw_r2r (mm0, mm1);        // unpack low src1 bytes
156     punpckhbw_r2r (mm0, mm2);        // unpack high src1 bytes
157
158     movq_m2r (*src2, mm3);        // load 8 src2 bytes
159     movq_r2r (mm3, mm4);        // copy 8 src2 bytes
160
161     punpcklbw_r2r (mm0, mm3);        // unpack low src2 bytes
162     punpckhbw_r2r (mm0, mm4);        // unpack high src2 bytes
163
164     paddw_r2r (mm3, mm1);        // add lows
165     paddw_r2r (mm4, mm2);        // add highs
166
167     // now have partials in mm1 and mm2
168
169     movq_m2r (*src3, mm3);        // load 8 src3 bytes
170     movq_r2r (mm3, mm4);        // copy 8 src3 bytes
171
172     punpcklbw_r2r (mm0, mm3);        // unpack low src3 bytes
173     punpckhbw_r2r (mm0, mm4);        // unpack high src3 bytes
174
175     paddw_r2r (mm3, mm1);        // add lows
176     paddw_r2r (mm4, mm2);        // add highs
177
178     movq_m2r (*src4, mm5);        // load 8 src4 bytes
179     movq_r2r (mm5, mm6);        // copy 8 src4 bytes
180
181     punpcklbw_r2r (mm0, mm5);        // unpack low src4 bytes
182     punpckhbw_r2r (mm0, mm6);        // unpack high src4 bytes
183
184     paddw_r2r (mm5, mm1);        // add lows
185     paddw_r2r (mm6, mm2);        // add highs
186
187     // now have subtotal in mm1 and mm2
188
189     paddw_m2r (round4, mm1);
190     psraw_i2r (2, mm1);                // /4
191     paddw_m2r (round4, mm2);
192     psraw_i2r (2, mm2);                // /4
193
194     packuswb_r2r (mm2, mm1);        // pack (w/ saturation)
195     movq_r2m (mm1, *dest);        // store result in dest
196 }
197
198 static inline void mmx_interp_average_4_U8 (yuv_data_t * dest,
199                                             yuv_data_t * src1, yuv_data_t * src2,
200                                             yuv_data_t * src3, yuv_data_t * src4)
201 {
202     //
203     // *dest = (*dest + (*src1 + *src2 + *src3 + *src4 + 2)/ 4 + 1)/ 2;
204     //
205
206     movq_m2r (*src1, mm1);        // load 8 src1 bytes
207     movq_r2r (mm1, mm2);        // copy 8 src1 bytes
208
209     punpcklbw_r2r (mm0, mm1);        // unpack low src1 bytes
210     punpckhbw_r2r (mm0, mm2);        // unpack high src1 bytes
211
212     movq_m2r (*src2, mm3);        // load 8 src2 bytes
213     movq_r2r (mm3, mm4);        // copy 8 src2 bytes
214
215     punpcklbw_r2r (mm0, mm3);        // unpack low src2 bytes
216     punpckhbw_r2r (mm0, mm4);        // unpack high src2 bytes
217
218     paddw_r2r (mm3, mm1);        // add lows
219     paddw_r2r (mm4, mm2);        // add highs
220
221     // now have partials in mm1 and mm2
222
223     movq_m2r (*src3, mm3);        // load 8 src3 bytes
224     movq_r2r (mm3, mm4);        // copy 8 src3 bytes
225
226     punpcklbw_r2r (mm0, mm3);        // unpack low src3 bytes
227     punpckhbw_r2r (mm0, mm4);        // unpack high src3 bytes
228
229     paddw_r2r (mm3, mm1);        // add lows
230     paddw_r2r (mm4, mm2);        // add highs
231
232     movq_m2r (*src4, mm5);        // load 8 src4 bytes
233     movq_r2r (mm5, mm6);        // copy 8 src4 bytes
234
235     punpcklbw_r2r (mm0, mm5);        // unpack low src4 bytes
236     punpckhbw_r2r (mm0, mm6);        // unpack high src4 bytes
237
238     paddw_r2r (mm5, mm1);        // add lows
239     paddw_r2r (mm6, mm2);        // add highs
240
241     paddw_m2r (round4, mm1);
242     psraw_i2r (2, mm1);                // /4
243     paddw_m2r (round4, mm2);
244     psraw_i2r (2, mm2);                // /4
245
246     // now have subtotal/4 in mm1 and mm2
247
248     movq_m2r (*dest, mm3);        // load 8 dest bytes
249     movq_r2r (mm3, mm4);        // copy 8 dest bytes
250
251     punpcklbw_r2r (mm0, mm3);        // unpack low dest bytes
252     punpckhbw_r2r (mm0, mm4);        // unpack high dest bytes
253
254     paddw_r2r (mm3, mm1);        // add lows
255     paddw_r2r (mm4, mm2);        // add highs
256
257     paddw_m2r (round1, mm1);
258     psraw_i2r (1, mm1);                // /2
259     paddw_m2r (round1, mm2);
260     psraw_i2r (1, mm2);                // /2
261
262     // now have end value in mm1 and mm2
263
264     packuswb_r2r (mm2, mm1);        // pack (w/ saturation)
265     movq_r2m (mm1,*dest);        // store result in dest
266 }
267
268 //-----------------------------------------------------------------------
269
270 static inline void MC_avg_mmx (int width, int height,
271                                yuv_data_t * dest, yuv_data_t * ref, int stride)
272 {
273     mmx_zero_reg ();
274
275     do {
276         mmx_average_2_U8 (dest, dest, ref);
277
278         if (width == 16)
279             mmx_average_2_U8 (dest+8, dest+8, ref+8);
280
281         dest += stride;
282         ref += stride;
283     } while (--height);
284 }
285
286 static void MC_avg_16_mmx (yuv_data_t * dest, yuv_data_t * ref,
287                            int stride, int height)
288 {
289     MC_avg_mmx (16, height, dest, ref, stride);
290 }
291
292 static void MC_avg_8_mmx (yuv_data_t * dest, yuv_data_t * ref,
293                           int stride, int height)
294 {
295     MC_avg_mmx (8, height, dest, ref, stride);
296 }
297
298 //-----------------------------------------------------------------------
299
300 static inline void MC_put_mmx (int width, int height,
301                                yuv_data_t * dest, yuv_data_t * ref, int stride)
302 {
303     mmx_zero_reg ();
304
305     do {
306         movq_m2r (* ref, mm1);        // load 8 ref bytes
307         movq_r2m (mm1,* dest);        // store 8 bytes at curr
308
309         if (width == 16)
310             {
311                 movq_m2r (* (ref+8), mm1);        // load 8 ref bytes
312                 movq_r2m (mm1,* (dest+8));        // store 8 bytes at curr
313             }
314
315         dest += stride;
316         ref += stride;
317     } while (--height);
318 }
319
320 static void MC_put_16_mmx (yuv_data_t * dest, yuv_data_t * ref,
321                            int stride, int height)
322 {
323     MC_put_mmx (16, height, dest, ref, stride);
324 }
325
326 static void MC_put_8_mmx (yuv_data_t * dest, yuv_data_t * ref,
327                           int stride, int height)
328 {
329     MC_put_mmx (8, height, dest, ref, stride);
330 }
331
332 //-----------------------------------------------------------------------
333
334 // Half pixel interpolation in the x direction
335 static inline void MC_avg_x_mmx (int width, int height,
336                                  yuv_data_t * dest, yuv_data_t * ref, int stride)
337 {
338     mmx_zero_reg ();
339
340     do {
341         mmx_interp_average_2_U8 (dest, ref, ref+1);
342
343         if (width == 16)
344             mmx_interp_average_2_U8 (dest+8, ref+8, ref+9);
345
346         dest += stride;
347         ref += stride;
348     } while (--height);
349 }
350
351 static void MC_avg_x16_mmx (yuv_data_t * dest, yuv_data_t * ref,
352                             int stride, int height)
353 {
354     MC_avg_x_mmx (16, height, dest, ref, stride);
355 }
356
357 static void MC_avg_x8_mmx (yuv_data_t * dest, yuv_data_t * ref,
358                            int stride, int height)
359 {
360     MC_avg_x_mmx (8, height, dest, ref, stride);
361 }
362
363 //-----------------------------------------------------------------------
364
365 static inline void MC_put_x_mmx (int width, int height,
366                                  yuv_data_t * dest, yuv_data_t * ref, int stride)
367 {
368     mmx_zero_reg ();
369
370     do {
371         mmx_average_2_U8 (dest, ref, ref+1);
372
373         if (width == 16)
374             mmx_average_2_U8 (dest+8, ref+8, ref+9);
375
376         dest += stride;
377         ref += stride;
378     } while (--height);
379 }
380
381 static void MC_put_x16_mmx (yuv_data_t * dest, yuv_data_t * ref,
382                             int stride, int height)
383 {
384     MC_put_x_mmx (16, height, dest, ref, stride);
385 }
386
387 static void MC_put_x8_mmx (yuv_data_t * dest, yuv_data_t * ref,
388                            int stride, int height)
389 {
390     MC_put_x_mmx (8, height, dest, ref, stride);
391 }
392
393 //-----------------------------------------------------------------------
394
395 static inline void MC_avg_xy_8wide_mmx (int height, yuv_data_t * dest,
396     yuv_data_t * ref, int stride)
397 {
398     pxor_r2r (mm0, mm0);
399     movq_m2r (round4, mm7);
400
401     movq_m2r (*ref, mm1);      // calculate first row ref[0] + ref[1]
402     movq_r2r (mm1, mm2);
403
404     punpcklbw_r2r (mm0, mm1);
405     punpckhbw_r2r (mm0, mm2);
406
407     movq_m2r (*(ref+1), mm3);
408     movq_r2r (mm3, mm4);
409
410     punpcklbw_r2r (mm0, mm3);
411     punpckhbw_r2r (mm0, mm4);
412
413     paddw_r2r (mm3, mm1);
414     paddw_r2r (mm4, mm2);
415
416     ref += stride;
417
418     do {
419
420         movq_m2r (*ref, mm5);   // calculate next row ref[0] + ref[1]
421         movq_r2r (mm5, mm6);
422
423         punpcklbw_r2r (mm0, mm5);
424         punpckhbw_r2r (mm0, mm6);
425
426         movq_m2r (*(ref+1), mm3);
427         movq_r2r (mm3, mm4);
428
429         punpcklbw_r2r (mm0, mm3);
430         punpckhbw_r2r (mm0, mm4);
431
432         paddw_r2r (mm3, mm5);
433         paddw_r2r (mm4, mm6);
434
435         movq_r2r (mm7, mm3);   // calculate round4 + previous row + current row
436         movq_r2r (mm7, mm4);
437
438         paddw_r2r (mm1, mm3);
439         paddw_r2r (mm2, mm4);
440
441         paddw_r2r (mm5, mm3);
442         paddw_r2r (mm6, mm4);
443
444         psraw_i2r (2, mm3);                // /4
445         psraw_i2r (2, mm4);                // /4
446
447         movq_m2r (*dest, mm1);   // calculate (subtotal + dest[0] + round1) / 2
448         movq_r2r (mm1, mm2);
449
450         punpcklbw_r2r (mm0, mm1);
451         punpckhbw_r2r (mm0, mm2);
452
453         paddw_r2r (mm1, mm3);
454         paddw_r2r (mm2, mm4);
455
456         paddw_m2r (round1, mm3);
457         paddw_m2r (round1, mm4);
458
459         psraw_i2r (1, mm3);                // /2
460         psraw_i2r (1, mm4);                // /2
461
462         packuswb_r2r (mm4, mm3);      // pack (w/ saturation)
463         movq_r2m (mm3, *dest);        // store result in dest
464
465         movq_r2r (mm5, mm1);    // remember current row for the next pass
466         movq_r2r (mm6, mm2);
467
468         ref += stride;
469         dest += stride;
470
471     } while (--height);
472 }
473
474 static void MC_avg_xy16_mmx (yuv_data_t * dest, yuv_data_t * ref,
475                              int stride, int height)
476 {
477     MC_avg_xy_8wide_mmx(height, dest, ref, stride);
478     MC_avg_xy_8wide_mmx(height, dest+8, ref+8, stride);
479 }
480
481 static void MC_avg_xy8_mmx (yuv_data_t * dest, yuv_data_t * ref,
482                             int stride, int height)
483 {
484     MC_avg_xy_8wide_mmx(height, dest, ref, stride);
485 }
486
487 //-----------------------------------------------------------------------
488
489 static inline void MC_put_xy_8wide_mmx (int height, yuv_data_t * dest,
490     yuv_data_t * ref, int stride)
491 {
492     pxor_r2r (mm0, mm0);
493     movq_m2r (round4, mm7);
494
495     movq_m2r (*ref, mm1);      // calculate first row ref[0] + ref[1]
496     movq_r2r (mm1, mm2);
497
498     punpcklbw_r2r (mm0, mm1);
499     punpckhbw_r2r (mm0, mm2);
500
501     movq_m2r (*(ref+1), mm3);
502     movq_r2r (mm3, mm4);
503
504     punpcklbw_r2r (mm0, mm3);
505     punpckhbw_r2r (mm0, mm4);
506
507     paddw_r2r (mm3, mm1);
508     paddw_r2r (mm4, mm2);
509
510     ref += stride;
511
512     do {
513
514         movq_m2r (*ref, mm5);   // calculate next row ref[0] + ref[1]
515         movq_r2r (mm5, mm6);
516
517         punpcklbw_r2r (mm0, mm5);
518         punpckhbw_r2r (mm0, mm6);
519
520         movq_m2r (*(ref+1), mm3);
521         movq_r2r (mm3, mm4);
522
523         punpcklbw_r2r (mm0, mm3);
524         punpckhbw_r2r (mm0, mm4);
525
526         paddw_r2r (mm3, mm5);
527         paddw_r2r (mm4, mm6);
528
529         movq_r2r (mm7, mm3);   // calculate round4 + previous row + current row
530         movq_r2r (mm7, mm4);
531
532         paddw_r2r (mm1, mm3);
533         paddw_r2r (mm2, mm4);
534
535         paddw_r2r (mm5, mm3);
536         paddw_r2r (mm6, mm4);
537
538         psraw_i2r (2, mm3);                // /4
539         psraw_i2r (2, mm4);                // /4
540
541         packuswb_r2r (mm4, mm3);      // pack (w/ saturation)
542         movq_r2m (mm3, *dest);        // store result in dest
543
544         movq_r2r (mm5, mm1);    // advance to the next row
545         movq_r2r (mm6, mm2);
546
547         ref += stride;
548         dest += stride;
549
550     } while (--height);
551 }
552
553 static void MC_put_xy16_mmx (yuv_data_t * dest, yuv_data_t * ref,
554                              int stride, int height)
555 {
556     MC_put_xy_8wide_mmx(height, dest, ref, stride);
557     MC_put_xy_8wide_mmx(height, dest + 8, ref + 8, stride);
558 }
559
560 static void MC_put_xy8_mmx (yuv_data_t * dest, yuv_data_t * ref,
561                             int stride, int height)
562 {
563     MC_put_xy_8wide_mmx(height, dest, ref, stride);
564 }
565
566 //-----------------------------------------------------------------------
567
568 static inline void MC_avg_y_mmx (int width, int height,
569                                  yuv_data_t * dest, yuv_data_t * ref, int stride)
570 {
571     yuv_data_t * ref_next = ref+stride;
572
573     mmx_zero_reg ();
574
575     do {
576         mmx_interp_average_2_U8 (dest, ref, ref_next);
577
578         if (width == 16)
579             mmx_interp_average_2_U8 (dest+8, ref+8, ref_next+8);
580
581         dest += stride;
582         ref += stride;
583         ref_next += stride;
584     } while (--height);
585 }
586
587 static void MC_avg_y16_mmx (yuv_data_t * dest, yuv_data_t * ref,
588                             int stride, int height)
589 {
590     MC_avg_y_mmx (16, height, dest, ref, stride);
591 }
592
593 static void MC_avg_y8_mmx (yuv_data_t * dest, yuv_data_t * ref,
594                            int stride, int height)
595 {
596     MC_avg_y_mmx (8, height, dest, ref, stride);
597 }
598
599 //-----------------------------------------------------------------------
600
601 static inline void MC_put_y_mmx (int width, int height,
602                                  yuv_data_t * dest, yuv_data_t * ref, int stride)
603 {
604     yuv_data_t * ref_next = ref+stride;
605
606     mmx_zero_reg ();
607
608     do {
609         mmx_average_2_U8 (dest, ref, ref_next);
610
611         if (width == 16)
612             mmx_average_2_U8 (dest+8, ref+8, ref_next+8);
613
614         dest += stride;
615         ref += stride;
616         ref_next += stride;
617     } while (--height);
618 }
619
620 static void MC_put_y16_mmx (yuv_data_t * dest, yuv_data_t * ref,
621                             int stride, int height)
622 {
623     MC_put_y_mmx (16, height, dest, ref, stride);
624 }
625
626 static void MC_put_y8_mmx (yuv_data_t * dest, yuv_data_t * ref,
627                            int stride, int height)
628 {
629     MC_put_y_mmx (8, height, dest, ref, stride);
630 }
631
632
633 /*****************************************************************************
634  * Functions exported as capabilities. They are declared as static so that
635  * we don't pollute the namespace too much.
636  *****************************************************************************/
637 static void (* ppppf_motion[2][2][4])( yuv_data_t *, yuv_data_t *, int, int ) =
638 {
639     /* Copying functions */
640     {
641         /* Width == 16 */
642         { MC_put_16_mmx, MC_put_x16_mmx, MC_put_y16_mmx, MC_put_xy16_mmx },
643         /* Width == 8 */        
644         { MC_put_8_mmx,  MC_put_x8_mmx,  MC_put_y8_mmx, MC_put_xy8_mmx }
645     },
646     /* Averaging functions */
647     {
648         /* Width == 16 */
649         { MC_avg_16_mmx, MC_avg_x16_mmx, MC_avg_y16_mmx, MC_avg_xy16_mmx },
650         /* Width == 8 */
651         { MC_avg_8_mmx,  MC_avg_x8_mmx,  MC_avg_y8_mmx,  MC_avg_xy8_mmx }
652     }
653 };
654
655 static int Open ( vlc_object_t *p_this )
656 {
657     p_this->p_private = ppppf_motion;
658     return VLC_SUCCESS;
659 }
660