Support for 9 and 10-bit encoding
[x262.git] / common / arm / mc-c.c
1 /*****************************************************************************
2  * mc-c.c: h264 encoder library (Motion Compensation)
3  *****************************************************************************
4  * Copyright (C) 2009 x264 project
5  *
6  * Authors: David Conrad <lessen42@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program 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
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 #include "common/common.h"
24 #include "mc.h"
25
26 void x264_prefetch_ref_arm( uint8_t *, int, int );
27 void x264_prefetch_fenc_arm( uint8_t *, int, uint8_t *, int, int );
28
29 void *x264_memcpy_aligned_neon( void * dst, const void * src, size_t n );
30 void x264_memzero_aligned_neon( void *dst, int n );
31
32 void x264_pixel_avg_16x16_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int, int );
33 void x264_pixel_avg_16x8_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int, int );
34 void x264_pixel_avg_8x16_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int, int );
35 void x264_pixel_avg_8x8_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int, int );
36 void x264_pixel_avg_8x4_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int, int );
37 void x264_pixel_avg_4x8_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int, int );
38 void x264_pixel_avg_4x4_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int, int );
39 void x264_pixel_avg_4x2_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int, int );
40
41 void x264_pixel_avg2_w4_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int );
42 void x264_pixel_avg2_w8_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int );
43 void x264_pixel_avg2_w16_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int );
44 void x264_pixel_avg2_w20_neon( uint8_t *, int, uint8_t *, int, uint8_t *, int );
45
46 #define MC_WEIGHT(func)\
47 void x264_mc_weight_w20##func##_neon( uint8_t *, int, uint8_t *, int, const x264_weight_t *, int );\
48 void x264_mc_weight_w16##func##_neon( uint8_t *, int, uint8_t *, int, const x264_weight_t *, int );\
49 void x264_mc_weight_w8##func##_neon( uint8_t *, int, uint8_t *, int, const x264_weight_t *, int );\
50 void x264_mc_weight_w4##func##_neon( uint8_t *, int, uint8_t *, int, const x264_weight_t *, int );\
51 \
52 static void (* const x264_mc##func##_wtab_neon[6])( uint8_t *, int, uint8_t *, int, const x264_weight_t *, int ) =\
53 {\
54     x264_mc_weight_w4##func##_neon,\
55     x264_mc_weight_w4##func##_neon,\
56     x264_mc_weight_w8##func##_neon,\
57     x264_mc_weight_w16##func##_neon,\
58     x264_mc_weight_w16##func##_neon,\
59     x264_mc_weight_w20##func##_neon,\
60 };
61
62 MC_WEIGHT()
63 MC_WEIGHT(_nodenom)
64 MC_WEIGHT(_offsetadd)
65 MC_WEIGHT(_offsetsub)
66
67 void x264_mc_copy_w4_neon( uint8_t *, int, uint8_t *, int, int );
68 void x264_mc_copy_w8_neon( uint8_t *, int, uint8_t *, int, int );
69 void x264_mc_copy_w16_neon( uint8_t *, int, uint8_t *, int, int );
70 void x264_mc_copy_w16_aligned_neon( uint8_t *, int, uint8_t *, int, int );
71
72 void x264_mc_chroma_neon( uint8_t *, int, uint8_t *, int, int, int, int, int );
73 void x264_frame_init_lowres_core_neon( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, int, int, int, int);
74
75 void x264_hpel_filter_v_neon( uint8_t *, uint8_t *, int16_t *, int, int );
76 void x264_hpel_filter_c_neon( uint8_t *, int16_t *, int );
77 void x264_hpel_filter_h_neon( uint8_t *, uint8_t *, int );
78
79 #if !X264_HIGH_BIT_DEPTH
80 static void x264_weight_cache_neon( x264_t *h, x264_weight_t *w )
81 {
82     if( w->i_scale == 1<<w->i_denom )
83     {
84         if( w->i_offset < 0 )
85         {
86             w->weightfn = x264_mc_offsetsub_wtab_neon;
87             w->cachea[0] = -w->i_offset;
88         }
89         else
90         {
91             w->weightfn = x264_mc_offsetadd_wtab_neon;
92             w->cachea[0] = w->i_offset;
93         }
94     }
95     else if( !w->i_denom )
96         w->weightfn = x264_mc_nodenom_wtab_neon;
97     else
98         w->weightfn = x264_mc_wtab_neon;
99 }
100
101 static void (* const x264_pixel_avg_wtab_neon[6])( uint8_t *, int, uint8_t *, int, uint8_t *, int ) =
102 {
103     NULL,
104     x264_pixel_avg2_w4_neon,
105     x264_pixel_avg2_w8_neon,
106     x264_pixel_avg2_w16_neon,   // no slower than w12, so no point in a separate function
107     x264_pixel_avg2_w16_neon,
108     x264_pixel_avg2_w20_neon,
109 };
110
111 static void (* const x264_mc_copy_wtab_neon[5])( uint8_t *, int, uint8_t *, int, int ) =
112 {
113     NULL,
114     x264_mc_copy_w4_neon,
115     x264_mc_copy_w8_neon,
116     NULL,
117     x264_mc_copy_w16_neon,
118 };
119
120 static const uint8_t hpel_ref0[16] = {0,1,1,1,0,1,1,1,2,3,3,3,0,1,1,1};
121 static const uint8_t hpel_ref1[16] = {0,0,0,0,2,2,3,2,2,2,3,2,2,2,3,2};
122
123 static void mc_luma_neon( uint8_t *dst,    int i_dst_stride,
124                           uint8_t *src[4], int i_src_stride,
125                           int mvx, int mvy,
126                           int i_width, int i_height, const x264_weight_t *weight )
127 {
128     int qpel_idx = ((mvy&3)<<2) + (mvx&3);
129     int offset = (mvy>>2)*i_src_stride + (mvx>>2);
130     uint8_t *src1 = src[hpel_ref0[qpel_idx]] + offset;
131     if ( (mvy&3) == 3 )             // explict if() to force conditional add
132         src1 += i_src_stride;
133
134     if( qpel_idx & 5 ) /* qpel interpolation needed */
135     {
136         uint8_t *src2 = src[hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);
137         x264_pixel_avg_wtab_neon[i_width>>2](
138                 dst, i_dst_stride, src1, i_src_stride,
139                 src2, i_height );
140         if( weight->weightfn )
141             weight->weightfn[i_width>>2]( dst, i_dst_stride, dst, i_dst_stride, weight, i_height );
142     }
143     else if( weight->weightfn )
144         weight->weightfn[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, weight, i_height );
145     else
146         x264_mc_copy_wtab_neon[i_width>>2]( dst, i_dst_stride, src1, i_src_stride, i_height );
147 }
148
149 static uint8_t *get_ref_neon( uint8_t *dst,   int *i_dst_stride,
150                               uint8_t *src[4], int i_src_stride,
151                               int mvx, int mvy,
152                               int i_width, int i_height, const x264_weight_t *weight )
153 {
154     int qpel_idx = ((mvy&3)<<2) + (mvx&3);
155     int offset = (mvy>>2)*i_src_stride + (mvx>>2);
156     uint8_t *src1 = src[hpel_ref0[qpel_idx]] + offset;
157     if ( (mvy&3) == 3 )             // explict if() to force conditional add
158         src1 += i_src_stride;
159
160     if( qpel_idx & 5 ) /* qpel interpolation needed */
161     {
162         uint8_t *src2 = src[hpel_ref1[qpel_idx]] + offset + ((mvx&3) == 3);
163         x264_pixel_avg_wtab_neon[i_width>>2](
164                 dst, *i_dst_stride, src1, i_src_stride,
165                 src2, i_height );
166         if( weight->weightfn )
167             weight->weightfn[i_width>>2]( dst, *i_dst_stride, dst, *i_dst_stride, weight, i_height );
168         return dst;
169     }
170     else if( weight->weightfn )
171     {
172         weight->weightfn[i_width>>2]( dst, *i_dst_stride, src1, i_src_stride, weight, i_height );
173         return dst;
174     }
175     else
176     {
177         *i_dst_stride = i_src_stride;
178         return src1;
179     }
180 }
181
182 static void hpel_filter_neon( uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, uint8_t *src,
183                               int stride, int width, int height, int16_t *buf )
184 {
185     int realign = (intptr_t)src & 15;
186     src -= realign;
187     dstv -= realign;
188     dstc -= realign;
189     dsth -= realign;
190     width += realign;
191     while( height-- )
192     {
193         x264_hpel_filter_v_neon( dstv, src, buf+8, stride, width );
194         x264_hpel_filter_c_neon( dstc, buf+8, width );
195         x264_hpel_filter_h_neon( dsth, src, width );
196         dsth += stride;
197         dstv += stride;
198         dstc += stride;
199         src  += stride;
200     }
201 }
202 #endif // !X264_HIGH_BIT_DEPTH
203
204 void x264_mc_init_arm( int cpu, x264_mc_functions_t *pf )
205 {
206     if( !(cpu&X264_CPU_ARMV6) )
207         return;
208
209 #if !X264_HIGH_BIT_DEPTH
210     pf->prefetch_fenc = x264_prefetch_fenc_arm;
211     pf->prefetch_ref  = x264_prefetch_ref_arm;
212 #endif // !X264_HIGH_BIT_DEPTH
213
214     if( !(cpu&X264_CPU_NEON) )
215         return;
216
217 #if !X264_HIGH_BIT_DEPTH
218     pf->copy_16x16_unaligned = x264_mc_copy_w16_neon;
219     pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_neon;
220     pf->copy[PIXEL_8x8]   = x264_mc_copy_w8_neon;
221     pf->copy[PIXEL_4x4]   = x264_mc_copy_w4_neon;
222
223     pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_neon;
224     pf->avg[PIXEL_16x8]  = x264_pixel_avg_16x8_neon;
225     pf->avg[PIXEL_8x16]  = x264_pixel_avg_8x16_neon;
226     pf->avg[PIXEL_8x8]   = x264_pixel_avg_8x8_neon;
227     pf->avg[PIXEL_8x4]   = x264_pixel_avg_8x4_neon;
228     pf->avg[PIXEL_4x8]   = x264_pixel_avg_4x8_neon;
229     pf->avg[PIXEL_4x4]   = x264_pixel_avg_4x4_neon;
230     pf->avg[PIXEL_4x2]   = x264_pixel_avg_4x2_neon;
231
232     pf->weight    = x264_mc_wtab_neon;
233     pf->offsetadd = x264_mc_offsetadd_wtab_neon;
234     pf->offsetsub = x264_mc_offsetsub_wtab_neon;
235     pf->weight_cache = x264_weight_cache_neon;
236
237     pf->mc_chroma = x264_mc_chroma_neon;
238     pf->mc_luma = mc_luma_neon;
239     pf->get_ref = get_ref_neon;
240     pf->hpel_filter = hpel_filter_neon;
241     pf->frame_init_lowres_core = x264_frame_init_lowres_core_neon;
242 #endif // !X264_HIGH_BIT_DEPTH
243
244 // Apple's gcc stupidly cannot align stack variables, and ALIGNED_ARRAY can't work on structs
245 #ifndef SYS_MACOSX
246     pf->memcpy_aligned  = x264_memcpy_aligned_neon;
247 #endif
248     pf->memzero_aligned = x264_memzero_aligned_neon;
249 }