]> git.sesse.net Git - ffmpeg/blob - libavcodec/ppc/dsputil_ppc.c
Original Commit: r22 | ods15 | 2006-09-22 13:49:56 +0300 (Fri, 22 Sep 2006) | 2 lines
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include "../dsputil.h"
22
23 #include "dsputil_ppc.h"
24
25 #ifdef HAVE_ALTIVEC
26 #include "dsputil_altivec.h"
27
28 extern void fdct_altivec(int16_t *block);
29 extern void gmc1_altivec(uint8_t *dst, uint8_t *src, int stride, int h,
30                          int x16, int y16, int rounder);
31 extern void idct_put_altivec(uint8_t *dest, int line_size, int16_t *block);
32 extern void idct_add_altivec(uint8_t *dest, int line_size, int16_t *block);
33
34 void dsputil_h264_init_ppc(DSPContext* c, AVCodecContext *avctx);
35
36 void dsputil_init_altivec(DSPContext* c, AVCodecContext *avctx);
37 void vc1dsp_init_altivec(DSPContext* c, AVCodecContext *avctx);
38 void snow_init_altivec(DSPContext* c, AVCodecContext *avctx);
39 void float_init_altivec(DSPContext* c, AVCodecContext *avctx);
40
41 #endif
42
43 int mm_flags = 0;
44
45 int mm_support(void)
46 {
47     int result = 0;
48 #ifdef HAVE_ALTIVEC
49     if (has_altivec()) {
50         result |= MM_ALTIVEC;
51     }
52 #endif /* result */
53     return result;
54 }
55
56 #ifdef POWERPC_PERFORMANCE_REPORT
57 unsigned long long perfdata[POWERPC_NUM_PMC_ENABLED][powerpc_perf_total][powerpc_data_total];
58 /* list below must match enum in dsputil_ppc.h */
59 static unsigned char* perfname[] = {
60   "ff_fft_calc_altivec",
61   "gmc1_altivec",
62   "dct_unquantize_h263_altivec",
63   "fdct_altivec",
64   "idct_add_altivec",
65   "idct_put_altivec",
66   "put_pixels16_altivec",
67   "avg_pixels16_altivec",
68   "avg_pixels8_altivec",
69   "put_pixels8_xy2_altivec",
70   "put_no_rnd_pixels8_xy2_altivec",
71   "put_pixels16_xy2_altivec",
72   "put_no_rnd_pixels16_xy2_altivec",
73   "hadamard8_diff8x8_altivec",
74   "hadamard8_diff16_altivec",
75   "avg_pixels8_xy2_altivec",
76   "clear_blocks_dcbz32_ppc",
77   "clear_blocks_dcbz128_ppc",
78   "put_h264_chroma_mc8_altivec",
79   "avg_h264_chroma_mc8_altivec",
80   "put_h264_qpel16_h_lowpass_altivec",
81   "avg_h264_qpel16_h_lowpass_altivec",
82   "put_h264_qpel16_v_lowpass_altivec",
83   "avg_h264_qpel16_v_lowpass_altivec",
84   "put_h264_qpel16_hv_lowpass_altivec",
85   "avg_h264_qpel16_hv_lowpass_altivec",
86   ""
87 };
88 #include <stdio.h>
89 #endif
90
91 #ifdef POWERPC_PERFORMANCE_REPORT
92 void powerpc_display_perf_report(void)
93 {
94   int i, j;
95   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");
96   for(i = 0 ; i < powerpc_perf_total ; i++)
97   {
98     for (j = 0; j < POWERPC_NUM_PMC_ENABLED ; j++)
99       {
100         if (perfdata[j][i][powerpc_data_num] != (unsigned long long)0)
101           av_log(NULL, AV_LOG_INFO,
102                   " Function \"%s\" (pmc%d):\n\tmin: %llu\n\tmax: %llu\n\tavg: %1.2lf (%llu)\n",
103                   perfname[i],
104                   j+1,
105                   perfdata[j][i][powerpc_data_min],
106                   perfdata[j][i][powerpc_data_max],
107                   (double)perfdata[j][i][powerpc_data_sum] /
108                   (double)perfdata[j][i][powerpc_data_num],
109                   perfdata[j][i][powerpc_data_num]);
110       }
111   }
112 }
113 #endif /* POWERPC_PERFORMANCE_REPORT */
114
115 /* ***** WARNING ***** WARNING ***** WARNING ***** */
116 /*
117   clear_blocks_dcbz32_ppc will not work properly
118   on PowerPC processors with a cache line size
119   not equal to 32 bytes.
120   Fortunately all processor used by Apple up to
121   at least the 7450 (aka second generation G4)
122   use 32 bytes cache line.
123   This is due to the use of the 'dcbz' instruction.
124   It simply clear to zero a single cache line,
125   so you need to know the cache line size to use it !
126   It's absurd, but it's fast...
127
128   update 24/06/2003 : Apple released yesterday the G5,
129   with a PPC970. cache line size : 128 bytes. Oups.
130   The semantic of dcbz was changed, it always clear
131   32 bytes. so the function below will work, but will
132   be slow. So I fixed check_dcbz_effect to use dcbzl,
133   which is defined to clear a cache line (as dcbz before).
134   So we still can distinguish, and use dcbz (32 bytes)
135   or dcbzl (one cache line) as required.
136
137   see <http://developer.apple.com/technotes/tn/tn2087.html>
138   and <http://developer.apple.com/technotes/tn/tn2086.html>
139 */
140 void clear_blocks_dcbz32_ppc(DCTELEM *blocks)
141 {
142 POWERPC_PERF_DECLARE(powerpc_clear_blocks_dcbz32, 1);
143     register int misal = ((unsigned long)blocks & 0x00000010);
144     register int i = 0;
145 POWERPC_PERF_START_COUNT(powerpc_clear_blocks_dcbz32, 1);
146 #if 1
147     if (misal) {
148       ((unsigned long*)blocks)[0] = 0L;
149       ((unsigned long*)blocks)[1] = 0L;
150       ((unsigned long*)blocks)[2] = 0L;
151       ((unsigned long*)blocks)[3] = 0L;
152       i += 16;
153     }
154     for ( ; i < sizeof(DCTELEM)*6*64-31 ; i += 32) {
155 #ifndef __MWERKS__
156       asm volatile("dcbz %0,%1" : : "b" (blocks), "r" (i) : "memory");
157 #else
158       __dcbz( blocks, i );
159 #endif
160     }
161     if (misal) {
162       ((unsigned long*)blocks)[188] = 0L;
163       ((unsigned long*)blocks)[189] = 0L;
164       ((unsigned long*)blocks)[190] = 0L;
165       ((unsigned long*)blocks)[191] = 0L;
166       i += 16;
167     }
168 #else
169     memset(blocks, 0, sizeof(DCTELEM)*6*64);
170 #endif
171 POWERPC_PERF_STOP_COUNT(powerpc_clear_blocks_dcbz32, 1);
172 }
173
174 /* same as above, when dcbzl clear a whole 128B cache line
175    i.e. the PPC970 aka G5 */
176 #ifndef NO_DCBZL
177 void clear_blocks_dcbz128_ppc(DCTELEM *blocks)
178 {
179 POWERPC_PERF_DECLARE(powerpc_clear_blocks_dcbz128, 1);
180     register int misal = ((unsigned long)blocks & 0x0000007f);
181     register int i = 0;
182 POWERPC_PERF_START_COUNT(powerpc_clear_blocks_dcbz128, 1);
183 #if 1
184  if (misal) {
185    // we could probably also optimize this case,
186    // but there's not much point as the machines
187    // aren't available yet (2003-06-26)
188       memset(blocks, 0, sizeof(DCTELEM)*6*64);
189     }
190     else
191       for ( ; i < sizeof(DCTELEM)*6*64 ; i += 128) {
192         asm volatile("dcbzl %0,%1" : : "b" (blocks), "r" (i) : "memory");
193       }
194 #else
195     memset(blocks, 0, sizeof(DCTELEM)*6*64);
196 #endif
197 POWERPC_PERF_STOP_COUNT(powerpc_clear_blocks_dcbz128, 1);
198 }
199 #else
200 void clear_blocks_dcbz128_ppc(DCTELEM *blocks)
201 {
202   memset(blocks, 0, sizeof(DCTELEM)*6*64);
203 }
204 #endif
205
206 #ifndef NO_DCBZL
207 /* check dcbz report how many bytes are set to 0 by dcbz */
208 /* update 24/06/2003 : replace dcbz by dcbzl to get
209    the intended effect (Apple "fixed" dcbz)
210    unfortunately this cannot be used unless the assembler
211    knows about dcbzl ... */
212 long check_dcbzl_effect(void)
213 {
214   register char *fakedata = (char*)av_malloc(1024);
215   register char *fakedata_middle;
216   register long zero = 0;
217   register long i = 0;
218   long count = 0;
219
220   if (!fakedata)
221   {
222     return 0L;
223   }
224
225   fakedata_middle = (fakedata + 512);
226
227   memset(fakedata, 0xFF, 1024);
228
229   /* below the constraint "b" seems to mean "Address base register"
230      in gcc-3.3 / RS/6000 speaks. seems to avoid using r0, so.... */
231   asm volatile("dcbzl %0, %1" : : "b" (fakedata_middle), "r" (zero));
232
233   for (i = 0; i < 1024 ; i ++)
234   {
235     if (fakedata[i] == (char)0)
236       count++;
237   }
238
239   av_free(fakedata);
240
241   return count;
242 }
243 #else
244 long check_dcbzl_effect(void)
245 {
246   return 0;
247 }
248 #endif
249
250 void dsputil_init_ppc(DSPContext* c, AVCodecContext *avctx)
251 {
252     // Common optimizations whether Altivec is available or not
253
254     switch (check_dcbzl_effect()) {
255         case 32:
256             c->clear_blocks = clear_blocks_dcbz32_ppc;
257             break;
258         case 128:
259             c->clear_blocks = clear_blocks_dcbz128_ppc;
260             break;
261         default:
262             break;
263     }
264
265 #ifdef HAVE_ALTIVEC
266     dsputil_h264_init_ppc(c, avctx);
267
268     if (has_altivec()) {
269         mm_flags |= MM_ALTIVEC;
270
271         dsputil_init_altivec(c, avctx);
272         snow_init_altivec(c, avctx);
273         vc1dsp_init_altivec(c, avctx);
274         float_init_altivec(c, avctx);
275         c->gmc1 = gmc1_altivec;
276
277 #ifdef CONFIG_ENCODERS
278         if (avctx->dct_algo == FF_DCT_AUTO ||
279             avctx->dct_algo == FF_DCT_ALTIVEC)
280         {
281             c->fdct = fdct_altivec;
282         }
283 #endif //CONFIG_ENCODERS
284
285         if (avctx->lowres==0)
286         {
287         if ((avctx->idct_algo == FF_IDCT_AUTO) ||
288                 (avctx->idct_algo == FF_IDCT_ALTIVEC))
289         {
290             c->idct_put = idct_put_altivec;
291             c->idct_add = idct_add_altivec;
292         #ifndef ALTIVEC_USE_REFERENCE_C_CODE
293             c->idct_permutation_type = FF_TRANSPOSE_IDCT_PERM;
294         #else /* ALTIVEC_USE_REFERENCE_C_CODE */
295             c->idct_permutation_type = FF_NO_IDCT_PERM;
296         #endif /* ALTIVEC_USE_REFERENCE_C_CODE */
297         }
298         }
299
300 #ifdef POWERPC_PERFORMANCE_REPORT
301         {
302           int i, j;
303           for (i = 0 ; i < powerpc_perf_total ; i++)
304           {
305             for (j = 0; j < POWERPC_NUM_PMC_ENABLED ; j++)
306               {
307                 perfdata[j][i][powerpc_data_min] = 0xFFFFFFFFFFFFFFFFULL;
308                 perfdata[j][i][powerpc_data_max] = 0x0000000000000000ULL;
309                 perfdata[j][i][powerpc_data_sum] = 0x0000000000000000ULL;
310                 perfdata[j][i][powerpc_data_num] = 0x0000000000000000ULL;
311               }
312           }
313         }
314 #endif /* POWERPC_PERFORMANCE_REPORT */
315     } else
316 #endif /* HAVE_ALTIVEC */
317     {
318         // Non-AltiVec PPC optimisations
319
320         // ... pending ...
321     }
322 }