]> git.sesse.net Git - ffmpeg/blob - libavcodec/ppc/hpeldsp_altivec.c
Merge commit '34e6af9e204ca6bb18d8cf8ec68fe19b0e083e95'
[ffmpeg] / libavcodec / ppc / hpeldsp_altivec.c
1 /*
2  * Copyright (c) 2002 Brian Foley
3  * Copyright (c) 2002 Dieter Shirley
4  * Copyright (c) 2003-2004 Romain Dolbeau <romain@dolbeau.org>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 #include "config.h"
24 #include "libavutil/cpu.h"
25 #include "libavcodec/hpeldsp.h"
26
27 #if HAVE_ALTIVEC
28 #if HAVE_ALTIVEC_H
29 #include <altivec.h>
30 #endif
31 #include "libavutil/ppc/types_altivec.h"
32 #include "libavutil/ppc/util_altivec.h"
33 #include "dsputil_altivec.h"
34
35 /* next one assumes that ((line_size % 16) == 0) */
36 void ff_put_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
37 {
38     register vector unsigned char pixelsv1, pixelsv2;
39     register vector unsigned char pixelsv1B, pixelsv2B;
40     register vector unsigned char pixelsv1C, pixelsv2C;
41     register vector unsigned char pixelsv1D, pixelsv2D;
42
43     register vector unsigned char perm = vec_lvsl(0, pixels);
44     int i;
45     register ptrdiff_t line_size_2 = line_size << 1;
46     register ptrdiff_t line_size_3 = line_size + line_size_2;
47     register ptrdiff_t line_size_4 = line_size << 2;
48
49 // hand-unrolling the loop by 4 gains about 15%
50 // mininum execution time goes from 74 to 60 cycles
51 // it's faster than -funroll-loops, but using
52 // -funroll-loops w/ this is bad - 74 cycles again.
53 // all this is on a 7450, tuning for the 7450
54     for (i = 0; i < h; i += 4) {
55         pixelsv1  = vec_ld( 0, pixels);
56         pixelsv2  = vec_ld(15, pixels);
57         pixelsv1B = vec_ld(line_size, pixels);
58         pixelsv2B = vec_ld(15 + line_size, pixels);
59         pixelsv1C = vec_ld(line_size_2, pixels);
60         pixelsv2C = vec_ld(15 + line_size_2, pixels);
61         pixelsv1D = vec_ld(line_size_3, pixels);
62         pixelsv2D = vec_ld(15 + line_size_3, pixels);
63         vec_st(vec_perm(pixelsv1, pixelsv2, perm),
64                0, (unsigned char*)block);
65         vec_st(vec_perm(pixelsv1B, pixelsv2B, perm),
66                line_size, (unsigned char*)block);
67         vec_st(vec_perm(pixelsv1C, pixelsv2C, perm),
68                line_size_2, (unsigned char*)block);
69         vec_st(vec_perm(pixelsv1D, pixelsv2D, perm),
70                line_size_3, (unsigned char*)block);
71         pixels+=line_size_4;
72         block +=line_size_4;
73     }
74 }
75
76 /* next one assumes that ((line_size % 16) == 0) */
77 #define op_avg(a,b)  a = ( ((a)|(b)) - ((((a)^(b))&0xFEFEFEFEUL)>>1) )
78 void ff_avg_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
79 {
80     register vector unsigned char pixelsv1, pixelsv2, pixelsv, blockv;
81     register vector unsigned char perm = vec_lvsl(0, pixels);
82     int i;
83
84     for (i = 0; i < h; i++) {
85         pixelsv1 = vec_ld( 0, pixels);
86         pixelsv2 = vec_ld(16,pixels);
87         blockv = vec_ld(0, block);
88         pixelsv = vec_perm(pixelsv1, pixelsv2, perm);
89         blockv = vec_avg(blockv,pixelsv);
90         vec_st(blockv, 0, (unsigned char*)block);
91         pixels+=line_size;
92         block +=line_size;
93     }
94 }
95
96 /* next one assumes that ((line_size % 8) == 0) */
97 static void avg_pixels8_altivec(uint8_t * block, const uint8_t * pixels, ptrdiff_t line_size, int h)
98 {
99     register vector unsigned char pixelsv1, pixelsv2, pixelsv, blockv;
100     int i;
101
102    for (i = 0; i < h; i++) {
103        /* block is 8 bytes-aligned, so we're either in the
104           left block (16 bytes-aligned) or in the right block (not) */
105        int rightside = ((unsigned long)block & 0x0000000F);
106
107        blockv = vec_ld(0, block);
108        pixelsv1 = vec_ld( 0, pixels);
109        pixelsv2 = vec_ld(16, pixels);
110        pixelsv = vec_perm(pixelsv1, pixelsv2, vec_lvsl(0, pixels));
111
112        if (rightside) {
113            pixelsv = vec_perm(blockv, pixelsv, vcprm(0,1,s0,s1));
114        } else {
115            pixelsv = vec_perm(blockv, pixelsv, vcprm(s0,s1,2,3));
116        }
117
118        blockv = vec_avg(blockv, pixelsv);
119
120        vec_st(blockv, 0, block);
121
122        pixels += line_size;
123        block += line_size;
124    }
125 }
126
127 /* next one assumes that ((line_size % 8) == 0) */
128 static void put_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
129 {
130     register int i;
131     register vector unsigned char pixelsv1, pixelsv2, pixelsavg;
132     register vector unsigned char blockv, temp1, temp2;
133     register vector unsigned short pixelssum1, pixelssum2, temp3;
134     register const vector unsigned char vczero = (const vector unsigned char)vec_splat_u8(0);
135     register const vector unsigned short vctwo = (const vector unsigned short)vec_splat_u16(2);
136
137     temp1 = vec_ld(0, pixels);
138     temp2 = vec_ld(16, pixels);
139     pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
140     if ((((unsigned long)pixels) & 0x0000000F) ==  0x0000000F) {
141         pixelsv2 = temp2;
142     } else {
143         pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
144     }
145     pixelsv1 = vec_mergeh(vczero, pixelsv1);
146     pixelsv2 = vec_mergeh(vczero, pixelsv2);
147     pixelssum1 = vec_add((vector unsigned short)pixelsv1,
148                          (vector unsigned short)pixelsv2);
149     pixelssum1 = vec_add(pixelssum1, vctwo);
150
151     for (i = 0; i < h ; i++) {
152         int rightside = ((unsigned long)block & 0x0000000F);
153         blockv = vec_ld(0, block);
154
155         temp1 = vec_ld(line_size, pixels);
156         temp2 = vec_ld(line_size + 16, pixels);
157         pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
158         if (((((unsigned long)pixels) + line_size) & 0x0000000F) ==  0x0000000F) {
159             pixelsv2 = temp2;
160         } else {
161             pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
162         }
163
164         pixelsv1 = vec_mergeh(vczero, pixelsv1);
165         pixelsv2 = vec_mergeh(vczero, pixelsv2);
166         pixelssum2 = vec_add((vector unsigned short)pixelsv1,
167                              (vector unsigned short)pixelsv2);
168         temp3 = vec_add(pixelssum1, pixelssum2);
169         temp3 = vec_sra(temp3, vctwo);
170         pixelssum1 = vec_add(pixelssum2, vctwo);
171         pixelsavg = vec_packsu(temp3, (vector unsigned short) vczero);
172
173         if (rightside) {
174             blockv = vec_perm(blockv, pixelsavg, vcprm(0, 1, s0, s1));
175         } else {
176             blockv = vec_perm(blockv, pixelsavg, vcprm(s0, s1, 2, 3));
177         }
178
179         vec_st(blockv, 0, block);
180
181         block += line_size;
182         pixels += line_size;
183     }
184 }
185
186 /* next one assumes that ((line_size % 8) == 0) */
187 static void put_no_rnd_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
188 {
189     register int i;
190     register vector unsigned char pixelsv1, pixelsv2, pixelsavg;
191     register vector unsigned char blockv, temp1, temp2;
192     register vector unsigned short pixelssum1, pixelssum2, temp3;
193     register const vector unsigned char vczero = (const vector unsigned char)vec_splat_u8(0);
194     register const vector unsigned short vcone = (const vector unsigned short)vec_splat_u16(1);
195     register const vector unsigned short vctwo = (const vector unsigned short)vec_splat_u16(2);
196
197     temp1 = vec_ld(0, pixels);
198     temp2 = vec_ld(16, pixels);
199     pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
200     if ((((unsigned long)pixels) & 0x0000000F) ==  0x0000000F) {
201         pixelsv2 = temp2;
202     } else {
203         pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
204     }
205     pixelsv1 = vec_mergeh(vczero, pixelsv1);
206     pixelsv2 = vec_mergeh(vczero, pixelsv2);
207     pixelssum1 = vec_add((vector unsigned short)pixelsv1,
208                          (vector unsigned short)pixelsv2);
209     pixelssum1 = vec_add(pixelssum1, vcone);
210
211     for (i = 0; i < h ; i++) {
212         int rightside = ((unsigned long)block & 0x0000000F);
213         blockv = vec_ld(0, block);
214
215         temp1 = vec_ld(line_size, pixels);
216         temp2 = vec_ld(line_size + 16, pixels);
217         pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
218         if (((((unsigned long)pixels) + line_size) & 0x0000000F) ==  0x0000000F) {
219             pixelsv2 = temp2;
220         } else {
221             pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
222         }
223
224         pixelsv1 = vec_mergeh(vczero, pixelsv1);
225         pixelsv2 = vec_mergeh(vczero, pixelsv2);
226         pixelssum2 = vec_add((vector unsigned short)pixelsv1,
227                              (vector unsigned short)pixelsv2);
228         temp3 = vec_add(pixelssum1, pixelssum2);
229         temp3 = vec_sra(temp3, vctwo);
230         pixelssum1 = vec_add(pixelssum2, vcone);
231         pixelsavg = vec_packsu(temp3, (vector unsigned short) vczero);
232
233         if (rightside) {
234             blockv = vec_perm(blockv, pixelsavg, vcprm(0, 1, s0, s1));
235         } else {
236             blockv = vec_perm(blockv, pixelsavg, vcprm(s0, s1, 2, 3));
237         }
238
239         vec_st(blockv, 0, block);
240
241         block += line_size;
242         pixels += line_size;
243     }
244 }
245
246 /* next one assumes that ((line_size % 16) == 0) */
247 static void put_pixels16_xy2_altivec(uint8_t * block, const uint8_t * pixels, ptrdiff_t line_size, int h)
248 {
249     register int i;
250     register vector unsigned char pixelsv1, pixelsv2, pixelsv3, pixelsv4;
251     register vector unsigned char blockv, temp1, temp2;
252     register vector unsigned short temp3, temp4,
253         pixelssum1, pixelssum2, pixelssum3, pixelssum4;
254     register const vector unsigned char vczero = (const vector unsigned char)vec_splat_u8(0);
255     register const vector unsigned short vctwo = (const vector unsigned short)vec_splat_u16(2);
256
257     temp1 = vec_ld(0, pixels);
258     temp2 = vec_ld(16, pixels);
259     pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
260     if ((((unsigned long)pixels) & 0x0000000F) ==  0x0000000F) {
261         pixelsv2 = temp2;
262     } else {
263         pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
264     }
265     pixelsv3 = vec_mergel(vczero, pixelsv1);
266     pixelsv4 = vec_mergel(vczero, pixelsv2);
267     pixelsv1 = vec_mergeh(vczero, pixelsv1);
268     pixelsv2 = vec_mergeh(vczero, pixelsv2);
269     pixelssum3 = vec_add((vector unsigned short)pixelsv3,
270                          (vector unsigned short)pixelsv4);
271     pixelssum3 = vec_add(pixelssum3, vctwo);
272     pixelssum1 = vec_add((vector unsigned short)pixelsv1,
273                          (vector unsigned short)pixelsv2);
274     pixelssum1 = vec_add(pixelssum1, vctwo);
275
276     for (i = 0; i < h ; i++) {
277         blockv = vec_ld(0, block);
278
279         temp1 = vec_ld(line_size, pixels);
280         temp2 = vec_ld(line_size + 16, pixels);
281         pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
282         if (((((unsigned long)pixels) + line_size) & 0x0000000F) ==  0x0000000F) {
283             pixelsv2 = temp2;
284         } else {
285             pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
286         }
287
288         pixelsv3 = vec_mergel(vczero, pixelsv1);
289         pixelsv4 = vec_mergel(vczero, pixelsv2);
290         pixelsv1 = vec_mergeh(vczero, pixelsv1);
291         pixelsv2 = vec_mergeh(vczero, pixelsv2);
292
293         pixelssum4 = vec_add((vector unsigned short)pixelsv3,
294                              (vector unsigned short)pixelsv4);
295         pixelssum2 = vec_add((vector unsigned short)pixelsv1,
296                              (vector unsigned short)pixelsv2);
297         temp4 = vec_add(pixelssum3, pixelssum4);
298         temp4 = vec_sra(temp4, vctwo);
299         temp3 = vec_add(pixelssum1, pixelssum2);
300         temp3 = vec_sra(temp3, vctwo);
301
302         pixelssum3 = vec_add(pixelssum4, vctwo);
303         pixelssum1 = vec_add(pixelssum2, vctwo);
304
305         blockv = vec_packsu(temp3, temp4);
306
307         vec_st(blockv, 0, block);
308
309         block += line_size;
310         pixels += line_size;
311     }
312 }
313
314 /* next one assumes that ((line_size % 16) == 0) */
315 static void put_no_rnd_pixels16_xy2_altivec(uint8_t * block, const uint8_t * pixels, ptrdiff_t line_size, int h)
316 {
317     register int i;
318     register vector unsigned char pixelsv1, pixelsv2, pixelsv3, pixelsv4;
319     register vector unsigned char blockv, temp1, temp2;
320     register vector unsigned short temp3, temp4,
321         pixelssum1, pixelssum2, pixelssum3, pixelssum4;
322     register const vector unsigned char vczero = (const vector unsigned char)vec_splat_u8(0);
323     register const vector unsigned short vcone = (const vector unsigned short)vec_splat_u16(1);
324     register const vector unsigned short vctwo = (const vector unsigned short)vec_splat_u16(2);
325
326     temp1 = vec_ld(0, pixels);
327     temp2 = vec_ld(16, pixels);
328     pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
329     if ((((unsigned long)pixels) & 0x0000000F) ==  0x0000000F) {
330         pixelsv2 = temp2;
331     } else {
332         pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
333     }
334     pixelsv3 = vec_mergel(vczero, pixelsv1);
335     pixelsv4 = vec_mergel(vczero, pixelsv2);
336     pixelsv1 = vec_mergeh(vczero, pixelsv1);
337     pixelsv2 = vec_mergeh(vczero, pixelsv2);
338     pixelssum3 = vec_add((vector unsigned short)pixelsv3,
339                          (vector unsigned short)pixelsv4);
340     pixelssum3 = vec_add(pixelssum3, vcone);
341     pixelssum1 = vec_add((vector unsigned short)pixelsv1,
342                          (vector unsigned short)pixelsv2);
343     pixelssum1 = vec_add(pixelssum1, vcone);
344
345     for (i = 0; i < h ; i++) {
346         blockv = vec_ld(0, block);
347
348         temp1 = vec_ld(line_size, pixels);
349         temp2 = vec_ld(line_size + 16, pixels);
350         pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
351         if (((((unsigned long)pixels) + line_size) & 0x0000000F) ==  0x0000000F) {
352             pixelsv2 = temp2;
353         } else {
354             pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
355         }
356
357         pixelsv3 = vec_mergel(vczero, pixelsv1);
358         pixelsv4 = vec_mergel(vczero, pixelsv2);
359         pixelsv1 = vec_mergeh(vczero, pixelsv1);
360         pixelsv2 = vec_mergeh(vczero, pixelsv2);
361
362         pixelssum4 = vec_add((vector unsigned short)pixelsv3,
363                              (vector unsigned short)pixelsv4);
364         pixelssum2 = vec_add((vector unsigned short)pixelsv1,
365                              (vector unsigned short)pixelsv2);
366         temp4 = vec_add(pixelssum3, pixelssum4);
367         temp4 = vec_sra(temp4, vctwo);
368         temp3 = vec_add(pixelssum1, pixelssum2);
369         temp3 = vec_sra(temp3, vctwo);
370
371         pixelssum3 = vec_add(pixelssum4, vcone);
372         pixelssum1 = vec_add(pixelssum2, vcone);
373
374         blockv = vec_packsu(temp3, temp4);
375
376         vec_st(blockv, 0, block);
377
378         block += line_size;
379         pixels += line_size;
380     }
381 }
382
383 /* next one assumes that ((line_size % 8) == 0) */
384 static void avg_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
385 {
386     register int i;
387     register vector unsigned char pixelsv1, pixelsv2, pixelsavg;
388     register vector unsigned char blockv, temp1, temp2, blocktemp;
389     register vector unsigned short pixelssum1, pixelssum2, temp3;
390
391     register const vector unsigned char vczero = (const vector unsigned char)
392                                         vec_splat_u8(0);
393     register const vector unsigned short vctwo = (const vector unsigned short)
394                                         vec_splat_u16(2);
395
396     temp1 = vec_ld(0, pixels);
397     temp2 = vec_ld(16, pixels);
398     pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
399     if ((((unsigned long)pixels) & 0x0000000F) ==  0x0000000F) {
400         pixelsv2 = temp2;
401     } else {
402         pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
403     }
404     pixelsv1 = vec_mergeh(vczero, pixelsv1);
405     pixelsv2 = vec_mergeh(vczero, pixelsv2);
406     pixelssum1 = vec_add((vector unsigned short)pixelsv1,
407                          (vector unsigned short)pixelsv2);
408     pixelssum1 = vec_add(pixelssum1, vctwo);
409
410     for (i = 0; i < h ; i++) {
411         int rightside = ((unsigned long)block & 0x0000000F);
412         blockv = vec_ld(0, block);
413
414         temp1 = vec_ld(line_size, pixels);
415         temp2 = vec_ld(line_size + 16, pixels);
416         pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
417         if (((((unsigned long)pixels) + line_size) & 0x0000000F) ==  0x0000000F) {
418             pixelsv2 = temp2;
419         } else {
420             pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
421         }
422
423         pixelsv1 = vec_mergeh(vczero, pixelsv1);
424         pixelsv2 = vec_mergeh(vczero, pixelsv2);
425         pixelssum2 = vec_add((vector unsigned short)pixelsv1,
426                              (vector unsigned short)pixelsv2);
427         temp3 = vec_add(pixelssum1, pixelssum2);
428         temp3 = vec_sra(temp3, vctwo);
429         pixelssum1 = vec_add(pixelssum2, vctwo);
430         pixelsavg = vec_packsu(temp3, (vector unsigned short) vczero);
431
432         if (rightside) {
433             blocktemp = vec_perm(blockv, pixelsavg, vcprm(0, 1, s0, s1));
434         } else {
435             blocktemp = vec_perm(blockv, pixelsavg, vcprm(s0, s1, 2, 3));
436         }
437
438         blockv = vec_avg(blocktemp, blockv);
439         vec_st(blockv, 0, block);
440
441         block += line_size;
442         pixels += line_size;
443     }
444 }
445 #endif /* HAVE_ALTIVEC */
446
447 void ff_hpeldsp_init_ppc(HpelDSPContext* c, int flags)
448 {
449 #if HAVE_ALTIVEC
450     int mm_flags = av_get_cpu_flags();
451
452     if (mm_flags & AV_CPU_FLAG_ALTIVEC) {
453         c->put_pixels_tab[0][0] = ff_put_pixels16_altivec;
454         c->put_no_rnd_pixels_tab[0][0] = ff_put_pixels16_altivec;
455         c->avg_pixels_tab[0][0] = ff_avg_pixels16_altivec;
456         c->avg_pixels_tab[1][0] = avg_pixels8_altivec;
457         c->avg_pixels_tab[1][3] = avg_pixels8_xy2_altivec;
458         c->put_pixels_tab[1][3] = put_pixels8_xy2_altivec;
459         c->put_no_rnd_pixels_tab[1][3] = put_no_rnd_pixels8_xy2_altivec;
460         c->put_pixels_tab[0][3] = put_pixels16_xy2_altivec;
461         c->put_no_rnd_pixels_tab[0][3] = put_no_rnd_pixels16_xy2_altivec;
462     }
463 #endif /* HAVE_ALTIVEC */
464 }