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
25 #include "libavutil/attributes.h"
26 #include "libavutil/cpu.h"
27 #include "libavutil/ppc/cpu.h"
28 #include "libavutil/ppc/util_altivec.h"
29
30 #include "libavcodec/avcodec.h"
31 #include "libavcodec/pixblockdsp.h"
32
33 #if HAVE_ALTIVEC
34
35 #if HAVE_VSX
get_pixels_altivec(int16_t * restrict block,const uint8_t * pixels,ptrdiff_t stride)36 static void get_pixels_altivec(int16_t *restrict block, const uint8_t *pixels,
37 ptrdiff_t stride)
38 {
39 int i;
40 vector unsigned char perm =
41 (vector unsigned char) {0x00,0x10, 0x01,0x11,0x02,0x12,0x03,0x13,\
42 0x04,0x14,0x05,0x15,0x06,0x16,0x07,0x17};
43 const vector unsigned char zero =
44 (const vector unsigned char) vec_splat_u8(0);
45
46 for (i = 0; i < 8; i++) {
47 /* Read potentially unaligned pixels.
48 * We're reading 16 pixels, and actually only want 8,
49 * but we simply ignore the extras. */
50 vector unsigned char bytes = vec_vsx_ld(0, pixels);
51
52 // Convert the bytes into shorts.
53 //vector signed short shorts = (vector signed short) vec_perm(zero, bytes, perm);
54 vector signed short shorts = (vector signed short) vec_perm(bytes, zero, perm);
55
56 // Save the data to the block, we assume the block is 16-byte aligned.
57 vec_vsx_st(shorts, i * 16, (vector signed short *) block);
58
59 pixels += stride;
60 }
61 }
62 #else
get_pixels_altivec(int16_t * restrict block,const uint8_t * pixels,ptrdiff_t stride)63 static void get_pixels_altivec(int16_t *restrict block, const uint8_t *pixels,
64 ptrdiff_t stride)
65 {
66 int i;
67 const vec_u8 zero = (const vec_u8)vec_splat_u8(0);
68
69 for (i = 0; i < 8; i++) {
70 vec_u8 perm = vec_lvsl(0, pixels);
71 /* Read potentially unaligned pixels.
72 * We're reading 16 pixels, and actually only want 8,
73 * but we simply ignore the extras. */
74 vec_u8 pixl = vec_ld(0, pixels);
75 vec_u8 pixr = vec_ld(7, pixels);
76 vec_u8 bytes = vec_perm(pixl, pixr, perm);
77
78 // Convert the bytes into shorts.
79 vec_s16 shorts = (vec_s16)vec_mergeh(zero, bytes);
80
81 // Save the data to the block, we assume the block is 16-byte aligned.
82 vec_st(shorts, i * 16, (vec_s16 *)block);
83
84 pixels += stride;
85 }
86 }
87
88 #endif /* HAVE_VSX */
89
90 #if HAVE_VSX
diff_pixels_altivec(int16_t * restrict block,const uint8_t * s1,const uint8_t * s2,ptrdiff_t stride)91 static void diff_pixels_altivec(int16_t *restrict block, const uint8_t *s1,
92 const uint8_t *s2, ptrdiff_t stride)
93 {
94 int i;
95 const vector unsigned char zero =
96 (const vector unsigned char) vec_splat_u8(0);
97 vector signed short shorts1, shorts2;
98
99 for (i = 0; i < 4; i++) {
100 /* Read potentially unaligned pixels.
101 * We're reading 16 pixels, and actually only want 8,
102 * but we simply ignore the extras. */
103 vector unsigned char bytes = vec_vsx_ld(0, s1);
104
105 // Convert the bytes into shorts.
106 shorts1 = (vector signed short) vec_mergeh(bytes, zero);
107
108 // Do the same for the second block of pixels.
109 bytes =vec_vsx_ld(0, s2);
110
111 // Convert the bytes into shorts.
112 shorts2 = (vector signed short) vec_mergeh(bytes, zero);
113
114 // Do the subtraction.
115 shorts1 = vec_sub(shorts1, shorts2);
116
117 // Save the data to the block, we assume the block is 16-byte aligned.
118 vec_vsx_st(shorts1, 0, (vector signed short *) block);
119
120 s1 += stride;
121 s2 += stride;
122 block += 8;
123
124 /* The code below is a copy of the code above...
125 * This is a manual unroll. */
126
127 /* Read potentially unaligned pixels.
128 * We're reading 16 pixels, and actually only want 8,
129 * but we simply ignore the extras. */
130 bytes = vec_vsx_ld(0, s1);
131
132 // Convert the bytes into shorts.
133 shorts1 = (vector signed short) vec_mergeh(bytes, zero);
134
135 // Do the same for the second block of pixels.
136 bytes = vec_vsx_ld(0, s2);
137
138 // Convert the bytes into shorts.
139 shorts2 = (vector signed short) vec_mergeh(bytes, zero);
140
141 // Do the subtraction.
142 shorts1 = vec_sub(shorts1, shorts2);
143
144 // Save the data to the block, we assume the block is 16-byte aligned.
145 vec_vsx_st(shorts1, 0, (vector signed short *) block);
146
147 s1 += stride;
148 s2 += stride;
149 block += 8;
150 }
151 }
152 #else
diff_pixels_altivec(int16_t * restrict block,const uint8_t * s1,const uint8_t * s2,ptrdiff_t stride)153 static void diff_pixels_altivec(int16_t *restrict block, const uint8_t *s1,
154 const uint8_t *s2, ptrdiff_t stride)
155 {
156 int i;
157 vec_u8 perm;
158 const vec_u8 zero = (const vec_u8)vec_splat_u8(0);
159 vec_s16 shorts1, shorts2;
160
161 for (i = 0; i < 4; i++) {
162 /* Read potentially unaligned pixels.
163 * We're reading 16 pixels, and actually only want 8,
164 * but we simply ignore the extras. */
165 perm = vec_lvsl(0, s1);
166 vec_u8 pixl = vec_ld(0, s1);
167 vec_u8 pixr = vec_ld(15, s1);
168 vec_u8 bytes = vec_perm(pixl, pixr, perm);
169
170 // Convert the bytes into shorts.
171 shorts1 = (vec_s16)vec_mergeh(zero, bytes);
172
173 // Do the same for the second block of pixels.
174 perm = vec_lvsl(0, s2);
175 pixl = vec_ld(0, s2);
176 pixr = vec_ld(15, s2);
177 bytes = vec_perm(pixl, pixr, perm);
178
179 // Convert the bytes into shorts.
180 shorts2 = (vec_s16)vec_mergeh(zero, bytes);
181
182 // Do the subtraction.
183 shorts1 = vec_sub(shorts1, shorts2);
184
185 // Save the data to the block, we assume the block is 16-byte aligned.
186 vec_st(shorts1, 0, (vec_s16 *)block);
187
188 s1 += stride;
189 s2 += stride;
190 block += 8;
191
192 /* The code below is a copy of the code above...
193 * This is a manual unroll. */
194
195 /* Read potentially unaligned pixels.
196 * We're reading 16 pixels, and actually only want 8,
197 * but we simply ignore the extras. */
198 perm = vec_lvsl(0, s1);
199 pixl = vec_ld(0, s1);
200 pixr = vec_ld(15, s1);
201 bytes = vec_perm(pixl, pixr, perm);
202
203 // Convert the bytes into shorts.
204 shorts1 = (vec_s16)vec_mergeh(zero, bytes);
205
206 // Do the same for the second block of pixels.
207 perm = vec_lvsl(0, s2);
208 pixl = vec_ld(0, s2);
209 pixr = vec_ld(15, s2);
210 bytes = vec_perm(pixl, pixr, perm);
211
212 // Convert the bytes into shorts.
213 shorts2 = (vec_s16)vec_mergeh(zero, bytes);
214
215 // Do the subtraction.
216 shorts1 = vec_sub(shorts1, shorts2);
217
218 // Save the data to the block, we assume the block is 16-byte aligned.
219 vec_st(shorts1, 0, (vec_s16 *)block);
220
221 s1 += stride;
222 s2 += stride;
223 block += 8;
224 }
225 }
226
227 #endif /* HAVE_VSX */
228
229 #endif /* HAVE_ALTIVEC */
230
231 #if HAVE_VSX
get_pixels_vsx(int16_t * restrict block,const uint8_t * pixels,ptrdiff_t stride)232 static void get_pixels_vsx(int16_t *restrict block, const uint8_t *pixels,
233 ptrdiff_t stride)
234 {
235 int i;
236 for (i = 0; i < 8; i++) {
237 vec_s16 shorts = vsx_ld_u8_s16(0, pixels);
238
239 vec_vsx_st(shorts, i * 16, block);
240
241 pixels += stride;
242 }
243 }
244
diff_pixels_vsx(int16_t * restrict block,const uint8_t * s1,const uint8_t * s2,ptrdiff_t stride)245 static void diff_pixels_vsx(int16_t *restrict block, const uint8_t *s1,
246 const uint8_t *s2, ptrdiff_t stride)
247 {
248 int i;
249 vec_s16 shorts1, shorts2;
250 for (i = 0; i < 8; i++) {
251 shorts1 = vsx_ld_u8_s16(0, s1);
252 shorts2 = vsx_ld_u8_s16(0, s2);
253
254 shorts1 = vec_sub(shorts1, shorts2);
255
256 vec_vsx_st(shorts1, 0, block);
257
258 s1 += stride;
259 s2 += stride;
260 block += 8;
261 }
262 }
263 #endif /* HAVE_VSX */
264
ff_pixblockdsp_init_ppc(PixblockDSPContext * c,AVCodecContext * avctx,unsigned high_bit_depth)265 av_cold void ff_pixblockdsp_init_ppc(PixblockDSPContext *c,
266 AVCodecContext *avctx,
267 unsigned high_bit_depth)
268 {
269 #if HAVE_ALTIVEC
270 if (!PPC_ALTIVEC(av_get_cpu_flags()))
271 return;
272
273 c->diff_pixels = diff_pixels_altivec;
274
275 if (!high_bit_depth) {
276 c->get_pixels = get_pixels_altivec;
277 }
278 #endif /* HAVE_ALTIVEC */
279
280 #if HAVE_VSX
281 if (!PPC_VSX(av_get_cpu_flags()))
282 return;
283
284 c->diff_pixels = diff_pixels_vsx;
285
286 if (!high_bit_depth)
287 c->get_pixels = get_pixels_vsx;
288 #endif /* HAVE_VSX */
289 }
290