]> git.sesse.net Git - vlc/blob - plugins/motion/motionaltivec.c
* Altivec IDCT and motion compensation, based on Paul Mackerras's mpeg2dec
[vlc] / plugins / motion / motionaltivec.c
1 /*****************************************************************************
2  * motionaltivec.c : Altivec motion compensation module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: motionaltivec.c,v 1.1 2001/09/05 16:07:49 massiot Exp $
6  *
7  * Authors: Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
8  *          Paul Mackerras <paulus@linuxcare.com.au>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program 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
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 #define MODULE_NAME motionaltivec
26 #include "modules_inner.h"
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include "defs.h"
32
33 #include <stdlib.h>                                      /* malloc(), free() */
34
35 #include "config.h"
36 #include "common.h"                                     /* boolean_t, byte_t */
37 #include "threads.h"
38 #include "mtime.h"
39 #include "tests.h"
40
41 #include "modules.h"
42 #include "modules_export.h"
43
44 /*****************************************************************************
45  * Local and extern prototypes.
46  *****************************************************************************/
47 static void motion_getfunctions( function_list_t * p_function_list );
48
49 /*****************************************************************************
50  * Build configuration tree.
51  *****************************************************************************/
52 MODULE_CONFIG_START
53 ADD_WINDOW( "Configuration for Altivec motion compensation module" )
54     ADD_COMMENT( "Ha, ha -- nothing to configure yet" )
55 MODULE_CONFIG_STOP
56
57 MODULE_INIT_START
58     p_module->i_capabilities = MODULE_CAPABILITY_NULL
59                                 | MODULE_CAPABILITY_MOTION;
60     p_module->psz_longname = "MMX motion compensation module";
61 MODULE_INIT_STOP
62
63 MODULE_ACTIVATE_START
64     motion_getfunctions( &p_module->p_functions->motion );
65 MODULE_ACTIVATE_STOP
66
67 MODULE_DEACTIVATE_START
68 MODULE_DEACTIVATE_STOP
69
70 /*****************************************************************************
71  * motion_Probe: tests probe the CPU and return a score
72  *****************************************************************************/
73 static int motion_Probe( probedata_t *p_data )
74 {
75     if( !TestCPU( CPU_CAPABILITY_ALTIVEC ) )
76     {
77         return( 0 );
78     }
79
80     if( TestMethod( MOTION_METHOD_VAR, "motionaltivec" )
81          || TestMethod( MOTION_METHOD_VAR, "altivec" ) )
82     {
83         return( 999 );
84     }
85
86     return( 150 );
87 }
88
89 /*****************************************************************************
90  * Motion compensation in Altivec
91  *****************************************************************************/
92
93 #define COPY_8(d, s)    (*(long long *)(d) = *(long long *)(s))
94 #define COPY_16(d, s)   (((long long *)(d))[0] = ((long long *)(s))[0], \
95                          ((long long *)(d))[1] = ((long long *)(s))[1])
96
97 void
98 MC_put_16_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
99 {
100         vector unsigned char rshift, refw0, refw1, d;
101
102         do {
103                 rshift = vec_lvsl(0, ref);
104                 refw0 = vec_ld(0, ref);
105                 refw1 = vec_ld(16, ref);
106                 d = vec_perm(refw0, refw1, rshift);
107                 if ((unsigned long)dest & 15) {
108                         /* unaligned store, yuck */
109                         vector unsigned char x = d;
110                         COPY_16(dest, &x);
111                 } else
112                         vec_st(d, 0, dest);
113                 ref += stride;
114                 dest += stride;
115         } while (--height);
116 }
117
118 void
119 MC_avg_16_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
120 {
121         vector unsigned char rshift, refw0, refw1;
122         vector unsigned char r, d;
123
124         do {
125                 rshift = vec_lvsl(0, ref);
126                 refw0 = vec_ld(0, ref);
127                 refw1 = vec_ld(16, ref);
128                 r = vec_perm(refw0, refw1, rshift);
129                 if ((unsigned long)dest & 15) {
130                         /* unaligned load/store, yuck */
131                         vector unsigned char dw0, dw1, dshift, mask;
132
133                         dshift = vec_lvsr(0, dest);
134                         dw0 = vec_ld(0, dest);
135                         dw1 = vec_ld(16, dest);
136                         d = vec_perm(r, r, dshift);
137                         mask = vec_perm((vector unsigned char)(0),
138                                         (vector unsigned char)(255), dshift);
139                         dw0 = vec_sel(dw0, vec_avg(dw0, d), mask);
140                         dw1 = vec_sel(vec_avg(dw1, d), dw1, mask);
141                         vec_st(dw0, 0, dest);
142                         vec_st(dw1, 16, dest);
143                 } else {
144                         d = vec_ld(0, dest);
145                         d = vec_avg(d, r);
146                         vec_st(d, 0, dest);
147                 }
148                 ref += stride;
149                 dest += stride;
150         } while (--height);
151 }
152
153 void
154 MC_put_x16_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
155 {
156         vector unsigned char rshift0, rshift1, refw0, refw1;
157         vector unsigned char t0, t1, d, one;
158
159         one = (vector unsigned char)(1);
160         do {
161                 rshift0 = vec_lvsl(0, ref);
162                 rshift1 = vec_add(rshift0, one);
163                 refw0 = vec_ld(0, ref);
164                 refw1 = vec_ld(16, ref);
165                 t0 = vec_perm(refw0, refw1, rshift0);
166                 t1 = vec_perm(refw0, refw1, rshift1);
167                 d = vec_avg(t0, t1);
168                 if ((unsigned long)dest & 15) {
169                         /* unaligned store, yuck */
170                         vector unsigned char x = d;
171                         COPY_16(dest, &x);
172                 } else
173                         vec_st(d, 0, dest);
174                 ref += stride;
175                 dest += stride;
176         } while (--height);
177 }
178
179 void
180 MC_avg_x16_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
181 {
182         vector unsigned char rshift0, rshift1, refw0, refw1;
183         vector unsigned char t0, t1, r, d, one;
184
185         one = (vector unsigned char)(1);
186         do {
187                 rshift0 = vec_lvsl(0, ref);
188                 rshift1 = vec_add(rshift0, one);
189                 refw0 = vec_ld(0, ref);
190                 refw1 = vec_ld(16, ref);
191                 t0 = vec_perm(refw0, refw1, rshift0);
192                 t1 = vec_perm(refw0, refw1, rshift1);
193                 r = vec_avg(t0, t1);
194                 if ((unsigned long)dest & 15) {
195                         /* unaligned load/store, yuck */
196                         vector unsigned char dw0, dw1, dshift, mask;
197
198                         dshift = vec_lvsr(0, dest);
199                         dw0 = vec_ld(0, dest);
200                         dw1 = vec_ld(16, dest);
201                         d = vec_perm(r, r, dshift);
202                         mask = vec_perm((vector unsigned char)(0),
203                                         (vector unsigned char)(255), dshift);
204                         dw0 = vec_sel(dw0, vec_avg(dw0, d), mask);
205                         dw1 = vec_sel(vec_avg(dw1, d), dw1, mask);
206                         vec_st(dw0, 0, dest);
207                         vec_st(dw1, 16, dest);
208                 } else {
209                         d = vec_ld(0, dest);
210                         d = vec_avg(d, r);
211                         vec_st(d, 0, dest);
212                 }
213                 ref += stride;
214                 dest += stride;
215         } while (--height);
216 }
217
218 void
219 MC_put_y16_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
220 {
221         vector unsigned char rshift, refw0, refw1;
222         vector unsigned char r0, r1, d;
223
224         rshift = vec_lvsl(0, ref);
225         refw0 = vec_ld(0, ref);
226         refw1 = vec_ld(16, ref);
227         r0 = vec_perm(refw0, refw1, rshift);
228         do {
229                 ref += stride;
230                 rshift = vec_lvsl(0, ref);
231                 refw0 = vec_ld(0, ref);
232                 refw1 = vec_ld(16, ref);
233                 r1 = vec_perm(refw0, refw1, rshift);
234                 d = vec_avg(r0, r1);
235                 r0 = r1;
236                 if ((unsigned long)dest & 15) {
237                         /* unaligned store, yuck */
238                         vector unsigned char x = d;
239                         COPY_16(dest, &x);
240                 } else
241                         vec_st(d, 0, dest);
242                 dest += stride;
243         } while (--height);
244 }
245
246 void
247 MC_avg_y16_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
248 {
249         vector unsigned char rshift, refw0, refw1;
250         vector unsigned char r0, r1, r, d;
251
252         rshift = vec_lvsl(0, ref);
253         refw0 = vec_ld(0, ref);
254         refw1 = vec_ld(16, ref);
255         r0 = vec_perm(refw0, refw1, rshift);
256         do {
257                 ref += stride;
258                 rshift = vec_lvsl(0, ref);
259                 refw0 = vec_ld(0, ref);
260                 refw1 = vec_ld(16, ref);
261                 r1 = vec_perm(refw0, refw1, rshift);
262                 r = vec_avg(r0, r1);
263                 r0 = r1;
264                 if ((unsigned long)dest & 15) {
265                         /* unaligned load/store, yuck */
266                         vector unsigned char dw0, dw1, dshift, mask;
267
268                         dshift = vec_lvsr(0, dest);
269                         dw0 = vec_ld(0, dest);
270                         dw1 = vec_ld(16, dest);
271                         d = vec_perm(r, r, dshift);
272                         mask = vec_perm((vector unsigned char)(0),
273                                         (vector unsigned char)(255), dshift);
274                         dw0 = vec_sel(dw0, vec_avg(dw0, d), mask);
275                         dw1 = vec_sel(vec_avg(dw1, d), dw1, mask);
276                         vec_st(dw0, 0, dest);
277                         vec_st(dw1, 16, dest);
278                 } else {
279                         d = vec_ld(0, dest);
280                         d = vec_avg(d, r);
281                         vec_st(d, 0, dest);
282                 }
283                 dest += stride;
284         } while (--height);
285 }
286
287 void
288 MC_put_xy16_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
289 {
290         vector unsigned char rshift0, rshift1, refw0, refw1;
291         vector unsigned char t0, t1, r0, r1, d, one;
292
293         rshift0 = vec_lvsl(0, ref);
294         one = (vector unsigned char)(1);
295         rshift1 = vec_add(rshift0, one);
296         refw0 = vec_ld(0, ref);
297         refw1 = vec_ld(16, ref);
298         t0 = vec_perm(refw0, refw1, rshift0);
299         t1 = vec_perm(refw0, refw1, rshift1);
300         r0 = vec_avg(t0, t1);
301         do {
302                 ref += stride;
303                 rshift0 = vec_lvsl(0, ref);
304                 rshift1 = vec_add(rshift0, one);
305                 refw0 = vec_ld(0, ref);
306                 refw1 = vec_ld(16, ref);
307                 t0 = vec_perm(refw0, refw1, rshift0);
308                 t1 = vec_perm(refw0, refw1, rshift1);
309                 r1 = vec_avg(t0, t1);
310                 d = vec_avg(r0, r1);
311                 r0 = r1;
312                 if ((unsigned long)dest & 15) {
313                         /* unaligned store, yuck */
314                         vector unsigned char x = d;
315                         COPY_16(dest, &x);
316                 } else
317                         vec_st(d, 0, dest);
318                 dest += stride;
319         } while (--height);
320 }
321
322 void
323 MC_avg_xy16_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
324 {
325         vector unsigned char rshift0, rshift1, refw0, refw1;
326         vector unsigned char t0, t1, r0, r1, r, d, one;
327
328         rshift0 = vec_lvsl(0, ref);
329         one = (vector unsigned char)(1);
330         rshift1 = vec_add(rshift0, one);
331         refw0 = vec_ld(0, ref);
332         refw1 = vec_ld(16, ref);
333         t0 = vec_perm(refw0, refw1, rshift0);
334         t1 = vec_perm(refw0, refw1, rshift1);
335         r0 = vec_avg(t0, t1);
336         do {
337                 ref += stride;
338                 rshift0 = vec_lvsl(0, ref);
339                 rshift1 = vec_add(rshift0, one);
340                 refw0 = vec_ld(0, ref);
341                 refw1 = vec_ld(16, ref);
342                 t0 = vec_perm(refw0, refw1, rshift0);
343                 t1 = vec_perm(refw0, refw1, rshift1);
344                 r1 = vec_avg(t0, t1);
345                 r = vec_avg(r0, r1);
346                 r0 = r1;
347                 if ((unsigned long)dest & 15) {
348                         /* unaligned load/store, yuck */
349                         vector unsigned char dw0, dw1, dshift, mask;
350
351                         dshift = vec_lvsr(0, dest);
352                         dw0 = vec_ld(0, dest);
353                         dw1 = vec_ld(16, dest);
354                         d = vec_perm(r, r, dshift);
355                         mask = vec_perm((vector unsigned char)(0),
356                                         (vector unsigned char)(255), dshift);
357                         dw0 = vec_sel(dw0, vec_avg(dw0, d), mask);
358                         dw1 = vec_sel(vec_avg(dw1, d), dw1, mask);
359                         vec_st(dw0, 0, dest);
360                         vec_st(dw1, 16, dest);
361                 } else {
362                         d = vec_ld(0, dest);
363                         d = vec_avg(d, r);
364                         vec_st(d, 0, dest);
365                 }
366                 dest += stride;
367         } while (--height);
368 }
369
370 void
371 MC_put_8_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
372 {
373         vector unsigned char rshift, refw0, refw1, d;
374
375         do {
376                 rshift = vec_lvsl(0, ref);
377                 refw0 = vec_ld(0, ref);
378                 refw1 = vec_ld(16, ref);
379                 d = vec_perm(refw0, refw1, rshift);
380                 COPY_8(dest, &d);
381                 ref += stride;
382                 dest += stride;
383         } while (--height);
384 }
385
386 void
387 MC_avg_8_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
388 {
389         vector unsigned char rshift, refw0, refw1;
390         vector unsigned char r, d;
391
392         do {
393                 rshift = vec_lvsl(0, ref);
394                 refw0 = vec_ld(0, ref);
395                 refw1 = vec_ld(16, ref);
396                 r = vec_perm(refw0, refw1, rshift);
397                 COPY_8(&d, dest);
398                 d = vec_avg(d, r);
399                 COPY_8(dest, &d);
400                 ref += stride;
401                 dest += stride;
402         } while (--height);
403 }
404
405 void
406 MC_put_x8_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
407 {
408         vector unsigned char rshift0, rshift1, refw0, refw1;
409         vector unsigned char t0, t1, d, one;
410
411         one = (vector unsigned char)(1);
412         do {
413                 rshift0 = vec_lvsl(0, ref);
414                 rshift1 = vec_add(rshift0, one);
415                 refw0 = vec_ld(0, ref);
416                 refw1 = vec_ld(16, ref);
417                 t0 = vec_perm(refw0, refw1, rshift0);
418                 t1 = vec_perm(refw0, refw1, rshift1);
419                 d = vec_avg(t0, t1);
420                 COPY_8(dest, &d);
421                 ref += stride;
422                 dest += stride;
423         } while (--height);
424 }
425
426 void
427 MC_avg_x8_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
428 {
429         vector unsigned char rshift0, rshift1, refw0, refw1;
430         vector unsigned char t0, t1, r, d, one;
431
432         one = (vector unsigned char)(1);
433         do {
434                 rshift0 = vec_lvsl(0, ref);
435                 rshift1 = vec_add(rshift0, one);
436                 refw0 = vec_ld(0, ref);
437                 refw1 = vec_ld(16, ref);
438                 t0 = vec_perm(refw0, refw1, rshift0);
439                 t1 = vec_perm(refw0, refw1, rshift1);
440                 r = vec_avg(t0, t1);
441                 COPY_8(&d, dest);
442                 d = vec_avg(d, r);
443                 COPY_8(dest, &d);
444                 ref += stride;
445                 dest += stride;
446         } while (--height);
447 }
448
449 void
450 MC_put_y8_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
451 {
452         vector unsigned char rshift, refw0, refw1;
453         vector unsigned char r0, r1, d;
454
455         rshift = vec_lvsl(0, ref);
456         refw0 = vec_ld(0, ref);
457         refw1 = vec_ld(16, ref);
458         r0 = vec_perm(refw0, refw1, rshift);
459         do {
460                 ref += stride;
461                 rshift = vec_lvsl(0, ref);
462                 refw0 = vec_ld(0, ref);
463                 refw1 = vec_ld(16, ref);
464                 r1 = vec_perm(refw0, refw1, rshift);
465                 d = vec_avg(r0, r1);
466                 r0 = r1;
467                 COPY_8(dest, &d);
468                 dest += stride;
469         } while (--height);
470 }
471
472 void
473 MC_avg_y8_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
474 {
475         vector unsigned char rshift, refw0, refw1;
476         vector unsigned char r0, r1, r, d;
477
478         rshift = vec_lvsl(0, ref);
479         refw0 = vec_ld(0, ref);
480         refw1 = vec_ld(16, ref);
481         r0 = vec_perm(refw0, refw1, rshift);
482         do {
483                 ref += stride;
484                 rshift = vec_lvsl(0, ref);
485                 refw0 = vec_ld(0, ref);
486                 refw1 = vec_ld(16, ref);
487                 r1 = vec_perm(refw0, refw1, rshift);
488                 r = vec_avg(r0, r1);
489                 r0 = r1;
490                 COPY_8(&d, dest);
491                 d = vec_avg(d, r);
492                 COPY_8(dest, &d);
493                 dest += stride;
494         } while (--height);
495 }
496
497 void
498 MC_put_xy8_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
499 {
500         vector unsigned char rshift0, rshift1, refw0, refw1;
501         vector unsigned char t0, t1, r0, r1, d, one;
502
503         rshift0 = vec_lvsl(0, ref);
504         one = (vector unsigned char)(1);
505         rshift1 = vec_add(rshift0, one);
506         refw0 = vec_ld(0, ref);
507         refw1 = vec_ld(16, ref);
508         t0 = vec_perm(refw0, refw1, rshift0);
509         t1 = vec_perm(refw0, refw1, rshift1);
510         r0 = vec_avg(t0, t1);
511         do {
512                 ref += stride;
513                 rshift0 = vec_lvsl(0, ref);
514                 rshift1 = vec_add(rshift0, one);
515                 refw0 = vec_ld(0, ref);
516                 refw1 = vec_ld(16, ref);
517                 t0 = vec_perm(refw0, refw1, rshift0);
518                 t1 = vec_perm(refw0, refw1, rshift1);
519                 r1 = vec_avg(t0, t1);
520                 d = vec_avg(r0, r1);
521                 r0 = r1;
522                 COPY_8(dest, &d);
523                 dest += stride;
524         } while (--height);
525 }
526
527 void
528 MC_avg_xy8_altivec(uint8_t * dest, uint8_t * ref, int stride, int height)
529 {
530         vector unsigned char rshift0, rshift1, refw0, refw1;
531         vector unsigned char t0, t1, r0, r1, r, d, one;
532
533         rshift0 = vec_lvsl(0, ref);
534         one = (vector unsigned char)(1);
535         rshift1 = vec_add(rshift0, one);
536         refw0 = vec_ld(0, ref);
537         refw1 = vec_ld(16, ref);
538         t0 = vec_perm(refw0, refw1, rshift0);
539         t1 = vec_perm(refw0, refw1, rshift1);
540         r0 = vec_avg(t0, t1);
541         do {
542                 ref += stride;
543                 rshift0 = vec_lvsl(0, ref);
544                 rshift1 = vec_add(rshift0, one);
545                 refw0 = vec_ld(0, ref);
546                 refw1 = vec_ld(16, ref);
547                 t0 = vec_perm(refw0, refw1, rshift0);
548                 t1 = vec_perm(refw0, refw1, rshift1);
549                 r1 = vec_avg(t0, t1);
550                 r = vec_avg(r0, r1);
551                 r0 = r1;
552                 COPY_8(&d, dest);
553                 d = vec_avg(d, r);
554                 COPY_8(dest, &d);
555                 dest += stride;
556         } while (--height);
557 }
558
559 /*****************************************************************************
560  * Functions exported as capabilities. They are declared as static so that
561  * we don't pollute the namespace too much.
562  *****************************************************************************/
563 static void motion_getfunctions( function_list_t * p_function_list )
564 {
565     static void (* ppppf_motion[2][2][4])( yuv_data_t *, yuv_data_t *,
566                                            int, int ) =
567     {
568         {
569             /* Copying functions */
570             {
571                 /* Width == 16 */
572                 MC_put_16_altivec, MC_put_x16_altivec, MC_put_y16_altivec, MC_put_xy16_altivec
573             },
574             {
575                 /* Width == 8 */
576                 MC_put_8_altivec,  MC_put_x8_altivec,  MC_put_y8_altivec, MC_put_xy8_altivec
577             }
578         },
579         {
580             /* Averaging functions */
581             {
582                 /* Width == 16 */
583                 MC_avg_16_altivec, MC_avg_x16_altivec, MC_avg_y16_altivec, MC_avg_xy16_altivec
584             },
585             {
586                 /* Width == 8 */
587                 MC_avg_8_altivec,  MC_avg_x8_altivec,  MC_avg_y8_altivec,  MC_avg_xy8_altivec
588             }
589         }
590     };
591
592     p_function_list->pf_probe = motion_Probe;
593
594 #define list p_function_list->functions.motion
595     memcpy( list.ppppf_motion, ppppf_motion, sizeof( void * ) * 16 );
596 #undef list
597
598     return;
599 }