drop support for pre-SSE3 assemblers
[x262.git] / common / x86 / mc-c.c
1 /*****************************************************************************
2  * mc-c.c: h264 encoder library (Motion Compensation)
3  *****************************************************************************
4  * Copyright (C) 2003-2008 x264 project
5  *
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *          Loren Merritt <lorenm@u.washington.edu>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "common/common.h"
29
30 /* NASM functions */
31 extern void x264_pixel_avg_16x16_sse2( uint8_t *, int, uint8_t *, int );
32 extern void x264_pixel_avg_16x8_sse2( uint8_t *, int, uint8_t *, int );
33 extern void x264_pixel_avg_16x16_mmxext( uint8_t *, int, uint8_t *, int );
34 extern void x264_pixel_avg_16x8_mmxext( uint8_t *, int, uint8_t *, int );
35 extern void x264_pixel_avg_8x16_mmxext( uint8_t *, int, uint8_t *, int );
36 extern void x264_pixel_avg_8x8_mmxext( uint8_t *, int, uint8_t *, int );
37 extern void x264_pixel_avg_8x4_mmxext( uint8_t *, int, uint8_t *, int );
38 extern void x264_pixel_avg_4x8_mmxext( uint8_t *, int, uint8_t *, int );
39 extern void x264_pixel_avg_4x4_mmxext( uint8_t *, int, uint8_t *, int );
40 extern void x264_pixel_avg_4x2_mmxext( uint8_t *, int, uint8_t *, int );
41 extern void x264_mc_copy_w4_mmx( uint8_t *, int, uint8_t *, int, int );
42 extern void x264_mc_copy_w8_mmx( uint8_t *, int, uint8_t *, int, int );
43 extern void x264_mc_copy_w16_mmx( uint8_t *, int, uint8_t *, int, int );
44 extern void x264_mc_copy_w16_sse2( uint8_t *, int, uint8_t *, int, int );
45 extern void x264_mc_copy_w16_sse3( uint8_t *, int, uint8_t *, int, int );
46 extern void x264_mc_copy_w16_aligned_sse2( uint8_t *, int, uint8_t *, int, int );
47 extern void x264_pixel_avg_weight_4x4_mmxext( uint8_t *, int, uint8_t *, int, int );
48 extern void x264_pixel_avg_weight_w8_mmxext( uint8_t *, int, uint8_t *, int, int, int );
49 extern void x264_pixel_avg_weight_w16_mmxext( uint8_t *, int, uint8_t *, int, int, int );
50 extern void x264_prefetch_fenc_mmxext( uint8_t *, int, uint8_t *, int, int );
51 extern void x264_prefetch_ref_mmxext( uint8_t *, int, int );
52 extern void x264_mc_chroma_mmxext( uint8_t *src, int i_src_stride,
53                                    uint8_t *dst, int i_dst_stride,
54                                    int dx, int dy, int i_width, int i_height );
55 extern void x264_plane_copy_mmxext( uint8_t *, int, uint8_t *, int, int w, int h);
56 extern void *x264_memcpy_aligned_mmx( void * dst, const void * src, size_t n );
57 extern void *x264_memcpy_aligned_sse2( void * dst, const void * src, size_t n );
58
59 #define PIXEL_AVG_W(width,cpu)\
60 extern void x264_pixel_avg2_w##width##_##cpu( uint8_t *, int, uint8_t *, int, uint8_t *, int );
61 /* This declares some functions that don't exist, but that isn't a problem. */
62 #define PIXEL_AVG_WALL(cpu)\
63 PIXEL_AVG_W(4,cpu); PIXEL_AVG_W(8,cpu); PIXEL_AVG_W(12,cpu); PIXEL_AVG_W(16,cpu); PIXEL_AVG_W(20,cpu);
64
65 PIXEL_AVG_WALL(mmxext)
66 PIXEL_AVG_WALL(cache32_mmxext)
67 PIXEL_AVG_WALL(cache64_mmxext)
68 PIXEL_AVG_WALL(cache64_sse2)
69 PIXEL_AVG_WALL(sse2)
70 PIXEL_AVG_WALL(sse3)
71
72 #define AVG_WEIGHT(W,H) \
73 void x264_pixel_avg_weight_ ## W ## x ## H ## _mmxext( uint8_t *dst, int i_dst, uint8_t *src, int i_src, int i_weight_dst ) \
74 { \
75     x264_pixel_avg_weight_w ## W ## _mmxext( dst, i_dst, src, i_src, i_weight_dst, H ); \
76 }
77 AVG_WEIGHT(16,16)
78 AVG_WEIGHT(16,8)
79 AVG_WEIGHT(8,16)
80 AVG_WEIGHT(8,8)
81 AVG_WEIGHT(8,4)
82
83 #define PIXEL_AVG_WTAB(instr, name1, name2, name3, name4, name5)\
84 static void (* const x264_pixel_avg_wtab_##instr[6])( uint8_t *, int, uint8_t *, int, uint8_t *, int ) =\
85 {\
86     NULL,\
87     x264_pixel_avg2_w4_##name1,\
88     x264_pixel_avg2_w8_##name2,\
89     x264_pixel_avg2_w12_##name3,\
90     x264_pixel_avg2_w16_##name4,\
91     x264_pixel_avg2_w20_##name5,\
92 };
93
94 /* w16 sse2 is faster than w12 mmx as long as the cacheline issue is resolved */
95 #define x264_pixel_avg2_w12_cache64_sse2 x264_pixel_avg2_w16_cache64_sse2
96 #define x264_pixel_avg2_w12_sse3         x264_pixel_avg2_w16_sse3
97
98 PIXEL_AVG_WTAB(mmxext, mmxext, mmxext, mmxext, mmxext, mmxext)
99 #ifdef ARCH_X86
100 PIXEL_AVG_WTAB(cache32_mmxext, mmxext, cache32_mmxext, cache32_mmxext, cache32_mmxext, cache32_mmxext)
101 #endif
102 PIXEL_AVG_WTAB(cache64_mmxext, mmxext, cache64_mmxext, cache64_mmxext, cache64_mmxext, cache64_mmxext)
103 PIXEL_AVG_WTAB(sse2, mmxext, mmxext, mmxext, sse2, sse2)
104 PIXEL_AVG_WTAB(cache64_sse2, mmxext, cache64_mmxext, cache64_sse2, cache64_sse2, cache64_sse2)
105 PIXEL_AVG_WTAB(cache64_sse3, mmxext, cache64_mmxext, sse3, sse3, sse3)
106
107 #define MC_COPY_WTAB(instr, name1, name2, name3)\
108 static void (* const x264_mc_copy_wtab_##instr[5])( uint8_t *, int, uint8_t *, int, int ) =\
109 {\
110     NULL,\
111     x264_mc_copy_w4_##name1,\
112     x264_mc_copy_w8_##name2,\
113     NULL,\
114     x264_mc_copy_w16_##name3,\
115 };
116
117 MC_COPY_WTAB(mmx,mmx,mmx,mmx)
118 MC_COPY_WTAB(sse2,mmx,mmx,sse2)
119 MC_COPY_WTAB(sse3,mmx,mmx,sse3)
120
121 static const int hpel_ref0[16] = {0,1,1,1,0,1,1,1,2,3,3,3,0,1,1,1};
122 static const int hpel_ref1[16] = {0,0,0,0,2,2,3,2,2,2,3,2,2,2,3,2};
123
124 #define MC_LUMA(name,instr1,instr2)\
125 void mc_luma_##name( uint8_t *dst,    int i_dst_stride,\
126                   uint8_t *src[4], int i_src_stride,\
127                   int mvx, int mvy,\
128                   int i_width, int i_height )\
129 {\
130     int qpel_idx = ((mvy&3)<<2) + (mvx&3);\
131     int offset = (mvy>>2)*i_src_stride + (mvx>>2);\
132     uint8_t *src1 = src[hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;\
133     if( qpel_idx & 5 ) /* qpel interpolation needed */\
134     {\
135         uint8_t *src2 = src[hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);\
136         x264_pixel_avg_wtab_##instr1[i_width>>2](\
137                 dst, i_dst_stride, src1, i_src_stride,\
138                 src2, i_height );\
139     }\
140     else\
141     {\
142         x264_mc_copy_wtab_##instr2[i_width>>2](\
143                 dst, i_dst_stride, src1, i_src_stride, i_height );\
144     }\
145 }
146
147 MC_LUMA(mmxext,mmxext,mmx)
148 #ifdef ARCH_X86
149 MC_LUMA(cache32_mmxext,cache32_mmxext,mmx)
150 MC_LUMA(cache64_mmxext,cache64_mmxext,mmx)
151 #endif
152 MC_LUMA(sse2,sse2,sse2)
153 MC_LUMA(cache64_sse2,cache64_sse2,sse2)
154 MC_LUMA(cache64_sse3,cache64_sse3,sse3)
155
156 #define GET_REF(name)\
157 uint8_t *get_ref_##name( uint8_t *dst,   int *i_dst_stride,\
158                          uint8_t *src[4], int i_src_stride,\
159                          int mvx, int mvy,\
160                          int i_width, int i_height )\
161 {\
162     int qpel_idx = ((mvy&3)<<2) + (mvx&3);\
163     int offset = (mvy>>2)*i_src_stride + (mvx>>2);\
164     uint8_t *src1 = src[hpel_ref0[qpel_idx]] + offset + ((mvy&3) == 3) * i_src_stride;\
165     if( qpel_idx & 5 ) /* qpel interpolation needed */\
166     {\
167         uint8_t *src2 = src[hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);\
168         x264_pixel_avg_wtab_##name[i_width>>2](\
169                 dst, *i_dst_stride, src1, i_src_stride,\
170                 src2, i_height );\
171         return dst;\
172     }\
173     else\
174     {\
175         *i_dst_stride = i_src_stride;\
176         return src1;\
177     }\
178 }
179
180 GET_REF(mmxext)
181 #ifdef ARCH_X86
182 GET_REF(cache32_mmxext)
183 GET_REF(cache64_mmxext)
184 #endif
185 GET_REF(sse2)
186 GET_REF(cache64_sse2)
187 GET_REF(cache64_sse3)
188
189 #define HPEL(align, cpu, cpuv, cpuc, cpuh)\
190 void x264_hpel_filter_v_##cpuv( uint8_t *dst, uint8_t *src, int16_t *buf, int stride, int width);\
191 void x264_hpel_filter_c_##cpuc( uint8_t *dst, int16_t *buf, int width );\
192 void x264_hpel_filter_h_##cpuh( uint8_t *dst, uint8_t *src, int width );\
193 void x264_sfence( void );\
194 void x264_hpel_filter_##cpu( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src,\
195                              int stride, int width, int height )\
196 {\
197     int16_t *buf;\
198     int realign = (long)src & (align-1);\
199     src -= realign;\
200     dstv -= realign;\
201     dstc -= realign;\
202     dsth -= realign;\
203     width += realign;\
204     buf = x264_malloc((width+16)*sizeof(int16_t));\
205     while( height-- )\
206     {\
207         x264_hpel_filter_v_##cpuv( dstv, src, buf+8, stride, width );\
208         x264_hpel_filter_c_##cpuc( dstc, buf+8, width );\
209         x264_hpel_filter_h_##cpuh( dsth, src, width );\
210         dsth += stride;\
211         dstv += stride;\
212         dstc += stride;\
213         src  += stride;\
214     }\
215     x264_sfence();\
216     x264_free(buf);\
217 }
218
219 HPEL(8, mmxext, mmxext, mmxext, mmxext)
220 HPEL(16, sse2_amd, mmxext, mmxext, sse2)
221 HPEL(16, sse2, sse2, sse2, sse2)
222 HPEL(16, ssse3, sse2, ssse3, sse2)
223
224 void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf )
225 {
226     if( !(cpu&X264_CPU_MMX) )
227         return;
228
229     pf->copy[PIXEL_16x16] = x264_mc_copy_w16_mmx;
230     pf->copy[PIXEL_8x8]   = x264_mc_copy_w8_mmx;
231     pf->copy[PIXEL_4x4]   = x264_mc_copy_w4_mmx;
232     pf->memcpy_aligned = x264_memcpy_aligned_mmx;
233
234     if( !(cpu&X264_CPU_MMXEXT) )
235         return;
236
237     pf->mc_luma = mc_luma_mmxext;
238     pf->get_ref = get_ref_mmxext;
239     pf->mc_chroma = x264_mc_chroma_mmxext;
240
241     pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_mmxext;
242     pf->avg[PIXEL_16x8]  = x264_pixel_avg_16x8_mmxext;
243     pf->avg[PIXEL_8x16]  = x264_pixel_avg_8x16_mmxext;
244     pf->avg[PIXEL_8x8]   = x264_pixel_avg_8x8_mmxext;
245     pf->avg[PIXEL_8x4]   = x264_pixel_avg_8x4_mmxext;
246     pf->avg[PIXEL_4x8]   = x264_pixel_avg_4x8_mmxext;
247     pf->avg[PIXEL_4x4]   = x264_pixel_avg_4x4_mmxext;
248     pf->avg[PIXEL_4x2]   = x264_pixel_avg_4x2_mmxext;
249     
250     pf->avg_weight[PIXEL_16x16] = x264_pixel_avg_weight_16x16_mmxext;
251     pf->avg_weight[PIXEL_16x8]  = x264_pixel_avg_weight_16x8_mmxext;
252     pf->avg_weight[PIXEL_8x16]  = x264_pixel_avg_weight_8x16_mmxext;
253     pf->avg_weight[PIXEL_8x8]   = x264_pixel_avg_weight_8x8_mmxext;
254     pf->avg_weight[PIXEL_8x4]   = x264_pixel_avg_weight_8x4_mmxext;
255     pf->avg_weight[PIXEL_4x4]   = x264_pixel_avg_weight_4x4_mmxext;
256     // avg_weight_4x8 is rare and 4x2 is not used
257
258     pf->plane_copy = x264_plane_copy_mmxext;
259     pf->hpel_filter = x264_hpel_filter_mmxext;
260
261     pf->prefetch_fenc = x264_prefetch_fenc_mmxext;
262     pf->prefetch_ref  = x264_prefetch_ref_mmxext;
263
264 #ifdef ARCH_X86 // all x86_64 cpus with cacheline split issues use sse2 instead
265     if( cpu&X264_CPU_CACHELINE_32 )
266     {
267         pf->mc_luma = mc_luma_cache32_mmxext;
268         pf->get_ref = get_ref_cache32_mmxext;
269     }
270     else if( cpu&X264_CPU_CACHELINE_SPLIT )
271     {
272         pf->mc_luma = mc_luma_cache64_mmxext;
273         pf->get_ref = get_ref_cache64_mmxext;
274     }
275 #endif
276
277     if( !(cpu&X264_CPU_SSE2) )
278         return;
279
280     pf->memcpy_aligned = x264_memcpy_aligned_sse2;
281     pf->hpel_filter = x264_hpel_filter_sse2_amd;
282
283     // disable on AMD processors since it is slower
284     if( cpu&X264_CPU_3DNOW )
285         return;
286
287     pf->mc_luma = mc_luma_sse2;
288     pf->get_ref = get_ref_sse2;
289     pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_sse2;
290     pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_sse2;
291     pf->avg[PIXEL_16x8]  = x264_pixel_avg_16x8_sse2;
292     pf->hpel_filter = x264_hpel_filter_sse2;
293
294     if( cpu&X264_CPU_CACHELINE_SPLIT )
295     {
296         pf->mc_luma = mc_luma_cache64_sse2;
297         pf->get_ref = get_ref_cache64_sse2;
298         /* lddqu doesn't work on Core2 */
299         if( (cpu&X264_CPU_SSE3) && !(cpu&X264_CPU_SSSE3) )
300         {
301             pf->mc_luma = mc_luma_cache64_sse3;
302             pf->get_ref = get_ref_cache64_sse3;
303         }
304     }
305
306     if( !(cpu&X264_CPU_SSSE3) )
307         return;
308
309     pf->hpel_filter = x264_hpel_filter_ssse3;
310 }