]> git.sesse.net Git - ffmpeg/blob - libavcodec/ppc/dsputil_ppc.c
hadamard/AltiVec: fix to compiler fix, again by (Romain Dolbeau <dolbeau at irisa...
[ffmpeg] / libavcodec / ppc / dsputil_ppc.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 library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "../dsputil.h"
22
23 #include "dsputil_ppc.h"
24
25 #ifdef HAVE_ALTIVEC
26 #include "dsputil_altivec.h"
27 #endif
28
29 extern void fdct_altivec(int16_t *block);
30 extern void idct_put_altivec(uint8_t *dest, int line_size, int16_t *block);
31 extern void idct_add_altivec(uint8_t *dest, int line_size, int16_t *block);
32
33 int mm_flags = 0;
34
35 int mm_support(void)
36 {
37     int result = 0;
38 #ifdef HAVE_ALTIVEC
39     if (has_altivec()) {
40         result |= MM_ALTIVEC;
41     }
42 #endif /* result */
43     return result;
44 }
45
46 #ifdef POWERPC_PERFORMANCE_REPORT
47 unsigned long long perfdata[POWERPC_NUM_PMC_ENABLED][powerpc_perf_total][powerpc_data_total];
48 /* list below must match enum in dsputil_ppc.h */
49 static unsigned char* perfname[] = {
50   "ff_fft_calc_altivec",
51   "gmc1_altivec",
52   "dct_unquantize_h263_altivec",
53   "fdct_altivec",
54   "idct_add_altivec",
55   "idct_put_altivec",
56   "put_pixels16_altivec",
57   "avg_pixels16_altivec",
58   "avg_pixels8_altivec",
59   "put_pixels8_xy2_altivec",
60   "put_no_rnd_pixels8_xy2_altivec",
61   "put_pixels16_xy2_altivec",
62   "put_no_rnd_pixels16_xy2_altivec",
63   "hadamard8_diff8x8_altivec",
64   "hadamard8_diff16_altivec",
65   "avg_pixels8_xy2_altivec",
66   "clear_blocks_dcbz32_ppc",
67   "clear_blocks_dcbz128_ppc"
68 };
69 #include <stdio.h>
70 #endif
71
72 #ifdef POWERPC_PERFORMANCE_REPORT
73 void powerpc_display_perf_report(void)
74 {
75   int i, j;
76   av_log(NULL, AV_LOG_INFO, "PowerPC performance report\n Values are from the PMC registers, and represent whatever the registers are set to record.\n");
77   for(i = 0 ; i < powerpc_perf_total ; i++)
78   {
79     for (j = 0; j < POWERPC_NUM_PMC_ENABLED ; j++)
80       {
81         if (perfdata[j][i][powerpc_data_num] != (unsigned long long)0)
82           av_log(NULL, AV_LOG_INFO,
83                   " Function \"%s\" (pmc%d):\n\tmin: %llu\n\tmax: %llu\n\tavg: %1.2lf (%llu)\n",
84                   perfname[i],
85                   j+1,
86                   perfdata[j][i][powerpc_data_min],
87                   perfdata[j][i][powerpc_data_max],
88                   (double)perfdata[j][i][powerpc_data_sum] /
89                   (double)perfdata[j][i][powerpc_data_num],
90                   perfdata[j][i][powerpc_data_num]);
91       }
92   }
93 }
94 #endif /* POWERPC_PERFORMANCE_REPORT */
95
96 /* ***** WARNING ***** WARNING ***** WARNING ***** */
97 /*
98   clear_blocks_dcbz32_ppc will not work properly
99   on PowerPC processors with a cache line size
100   not equal to 32 bytes.
101   Fortunately all processor used by Apple up to
102   at least the 7450 (aka second generation G4)
103   use 32 bytes cache line.
104   This is due to the use of the 'dcbz' instruction.
105   It simply clear to zero a single cache line,
106   so you need to know the cache line size to use it !
107   It's absurd, but it's fast...
108
109   update 24/06/2003 : Apple released yesterday the G5,
110   with a PPC970. cache line size : 128 bytes. Oups.
111   The semantic of dcbz was changed, it always clear
112   32 bytes. so the function below will work, but will
113   be slow. So I fixed check_dcbz_effect to use dcbzl,
114   which is defined to clear a cache line (as dcbz before).
115   So we still can distinguish, and use dcbz (32 bytes)
116   or dcbzl (one cache line) as required.
117
118   see <http://developer.apple.com/technotes/tn/tn2087.html>
119   and <http://developer.apple.com/technotes/tn/tn2086.html>
120 */
121 void clear_blocks_dcbz32_ppc(DCTELEM *blocks)
122 {
123 POWERPC_PERF_DECLARE(powerpc_clear_blocks_dcbz32, 1);
124     register int misal = ((unsigned long)blocks & 0x00000010);
125     register int i = 0;
126 POWERPC_PERF_START_COUNT(powerpc_clear_blocks_dcbz32, 1);
127 #if 1
128     if (misal) {
129       ((unsigned long*)blocks)[0] = 0L;
130       ((unsigned long*)blocks)[1] = 0L;
131       ((unsigned long*)blocks)[2] = 0L;
132       ((unsigned long*)blocks)[3] = 0L;
133       i += 16;
134     }
135     for ( ; i < sizeof(DCTELEM)*6*64 ; i += 32) {
136 #ifndef __MWERKS__
137       asm volatile("dcbz %0,%1" : : "b" (blocks), "r" (i) : "memory");
138 #else
139       __dcbz( blocks, i );
140 #endif
141     }
142     if (misal) {
143       ((unsigned long*)blocks)[188] = 0L;
144       ((unsigned long*)blocks)[189] = 0L;
145       ((unsigned long*)blocks)[190] = 0L;
146       ((unsigned long*)blocks)[191] = 0L;
147       i += 16;
148     }
149 #else
150     memset(blocks, 0, sizeof(DCTELEM)*6*64);
151 #endif
152 POWERPC_PERF_STOP_COUNT(powerpc_clear_blocks_dcbz32, 1);
153 }
154
155 /* same as above, when dcbzl clear a whole 128B cache line
156    i.e. the PPC970 aka G5 */
157 #ifndef NO_DCBZL
158 void clear_blocks_dcbz128_ppc(DCTELEM *blocks)
159 {
160 POWERPC_PERF_DECLARE(powerpc_clear_blocks_dcbz128, 1);
161     register int misal = ((unsigned long)blocks & 0x0000007f);
162     register int i = 0;
163 POWERPC_PERF_START_COUNT(powerpc_clear_blocks_dcbz128, 1);
164 #if 1
165  if (misal) {
166    // we could probably also optimize this case,
167    // but there's not much point as the machines
168    // aren't available yet (2003-06-26)
169       memset(blocks, 0, sizeof(DCTELEM)*6*64);
170     }
171     else
172       for ( ; i < sizeof(DCTELEM)*6*64 ; i += 128) {
173         asm volatile("dcbzl %0,%1" : : "b" (blocks), "r" (i) : "memory");
174       }
175 #else
176     memset(blocks, 0, sizeof(DCTELEM)*6*64);
177 #endif
178 POWERPC_PERF_STOP_COUNT(powerpc_clear_blocks_dcbz128, 1);
179 }
180 #else
181 void clear_blocks_dcbz128_ppc(DCTELEM *blocks)
182 {
183   memset(blocks, 0, sizeof(DCTELEM)*6*64);
184 }
185 #endif
186
187 #ifndef NO_DCBZL
188 /* check dcbz report how many bytes are set to 0 by dcbz */
189 /* update 24/06/2003 : replace dcbz by dcbzl to get
190    the intended effect (Apple "fixed" dcbz)
191    unfortunately this cannot be used unless the assembler
192    knows about dcbzl ... */
193 long check_dcbzl_effect(void)
194 {
195   register char *fakedata = (char*)av_malloc(1024);
196   register char *fakedata_middle;
197   register long zero = 0;
198   register long i = 0;
199   long count = 0;
200
201   if (!fakedata)
202   {
203     return 0L;
204   }
205
206   fakedata_middle = (fakedata + 512);
207
208   memset(fakedata, 0xFF, 1024);
209
210   /* below the constraint "b" seems to mean "Address base register"
211      in gcc-3.3 / RS/6000 speaks. seems to avoid using r0, so.... */
212   asm volatile("dcbzl %0, %1" : : "b" (fakedata_middle), "r" (zero));
213
214   for (i = 0; i < 1024 ; i ++)
215   {
216     if (fakedata[i] == (char)0)
217       count++;
218   }
219
220   av_free(fakedata);
221   
222   return count;
223 }
224 #else
225 long check_dcbzl_effect(void)
226 {
227   return 0;
228 }
229 #endif
230
231 void dsputil_init_ppc(DSPContext* c, AVCodecContext *avctx)
232 {
233     // Common optimizations whether Altivec is available or not
234
235   switch (check_dcbzl_effect()) {
236   case 32:
237     c->clear_blocks = clear_blocks_dcbz32_ppc;
238     break;
239   case 128:
240     c->clear_blocks = clear_blocks_dcbz128_ppc;
241     break;
242   default:
243     break;
244   }
245   
246 #ifdef HAVE_ALTIVEC
247     if (has_altivec()) {
248         mm_flags |= MM_ALTIVEC;
249         
250         // Altivec specific optimisations
251         c->pix_abs[0][1] = sad16_x2_altivec;
252         c->pix_abs[0][2] = sad16_y2_altivec;
253         c->pix_abs[0][3] = sad16_xy2_altivec;
254         c->pix_abs[0][0] = sad16_altivec;
255         c->pix_abs[1][0] = sad8_altivec;
256         c->sad[0]= sad16_altivec;
257         c->sad[1]= sad8_altivec;
258         c->pix_norm1 = pix_norm1_altivec;
259         c->sse[1]= sse8_altivec;
260         c->sse[0]= sse16_altivec;
261         c->pix_sum = pix_sum_altivec;
262         c->diff_pixels = diff_pixels_altivec;
263         c->get_pixels = get_pixels_altivec;
264 // next one disabled as it's untested.
265 #if 0
266         c->add_bytes= add_bytes_altivec;
267 #endif /* 0 */
268         c->put_pixels_tab[0][0] = put_pixels16_altivec;
269         /* the two functions do the same thing, so use the same code */
270         c->put_no_rnd_pixels_tab[0][0] = put_pixels16_altivec;
271         c->avg_pixels_tab[0][0] = avg_pixels16_altivec;
272         c->avg_pixels_tab[1][0] = avg_pixels8_altivec;
273         c->avg_pixels_tab[1][3] = avg_pixels8_xy2_altivec;
274         c->put_pixels_tab[1][3] = put_pixels8_xy2_altivec;
275         c->put_no_rnd_pixels_tab[1][3] = put_no_rnd_pixels8_xy2_altivec;
276         c->put_pixels_tab[0][3] = put_pixels16_xy2_altivec;
277         c->put_no_rnd_pixels_tab[0][3] = put_no_rnd_pixels16_xy2_altivec;
278         
279         c->gmc1 = gmc1_altivec;
280
281 #ifdef CONFIG_DARWIN // ATM gcc-3.3 and gcc-3.4 fail to compile these in linux...
282         c->hadamard8_diff[0] = hadamard8_diff16_altivec;
283         c->hadamard8_diff[1] = hadamard8_diff8x8_altivec;
284 #endif
285
286 #ifdef CONFIG_ENCODERS
287         if (avctx->dct_algo == FF_DCT_AUTO ||
288             avctx->dct_algo == FF_DCT_ALTIVEC)
289         {
290             c->fdct = fdct_altivec;
291         }
292 #endif //CONFIG_ENCODERS
293
294         if ((avctx->idct_algo == FF_IDCT_AUTO) ||
295                 (avctx->idct_algo == FF_IDCT_ALTIVEC))
296         {
297             c->idct_put = idct_put_altivec;
298             c->idct_add = idct_add_altivec;
299 #ifndef ALTIVEC_USE_REFERENCE_C_CODE
300             c->idct_permutation_type = FF_TRANSPOSE_IDCT_PERM;
301 #else /* ALTIVEC_USE_REFERENCE_C_CODE */
302             c->idct_permutation_type = FF_NO_IDCT_PERM;
303 #endif /* ALTIVEC_USE_REFERENCE_C_CODE */
304         }
305         
306 #ifdef POWERPC_PERFORMANCE_REPORT
307         {
308           int i, j;
309           for (i = 0 ; i < powerpc_perf_total ; i++)
310           {
311             for (j = 0; j < POWERPC_NUM_PMC_ENABLED ; j++)
312               {
313                 perfdata[j][i][powerpc_data_min] = (unsigned long long)0xFFFFFFFFFFFFFFFF;
314                 perfdata[j][i][powerpc_data_max] = (unsigned long long)0x0000000000000000;
315                 perfdata[j][i][powerpc_data_sum] = (unsigned long long)0x0000000000000000;
316                 perfdata[j][i][powerpc_data_num] = (unsigned long long)0x0000000000000000;
317               }
318           }
319         }
320 #endif /* POWERPC_PERFORMANCE_REPORT */
321     } else
322 #endif /* HAVE_ALTIVEC */
323     {
324         // Non-AltiVec PPC optimisations
325
326         // ... pending ...
327     }
328 }