1 /*
2 * Copyright (c) 2018 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "./vpx_config.h"
12
13 #include "./vp9_rtcd.h"
14 #include "vpx_dsp/ppc/types_vsx.h"
15
16 // Multiply the packed 16-bit integers in a and b, producing intermediate 32-bit
17 // integers, and return the high 16 bits of the intermediate integers.
18 // (a * b) >> 16
19 // Note: Because this is done in 2 operations, a and b cannot both be UINT16_MIN
vec_mulhi(int16x8_t a,int16x8_t b)20 static INLINE int16x8_t vec_mulhi(int16x8_t a, int16x8_t b) {
21 // madds does ((A * B) >> 15) + C, we need >> 16, so we perform an extra right
22 // shift.
23 return vec_sra(vec_madds(a, b, vec_zeros_s16), vec_ones_u16);
24 }
25
26 // Negate 16-bit integers in a when the corresponding signed 16-bit
27 // integer in b is negative.
vec_sign(int16x8_t a,int16x8_t b)28 static INLINE int16x8_t vec_sign(int16x8_t a, int16x8_t b) {
29 const int16x8_t mask = vec_sra(b, vec_shift_sign_s16);
30 return vec_xor(vec_add(a, mask), mask);
31 }
32
33 // Compare packed 16-bit integers across a, and return the maximum value in
34 // every element. Returns a vector containing the biggest value across vector a.
vec_max_across(int16x8_t a)35 static INLINE int16x8_t vec_max_across(int16x8_t a) {
36 a = vec_max(a, vec_perm(a, a, vec_perm64));
37 a = vec_max(a, vec_perm(a, a, vec_perm32));
38 return vec_max(a, vec_perm(a, a, vec_perm16));
39 }
40
vp9_quantize_fp_vsx(const tran_low_t * coeff_ptr,intptr_t n_coeffs,const int16_t * round_ptr,const int16_t * quant_ptr,tran_low_t * qcoeff_ptr,tran_low_t * dqcoeff_ptr,const int16_t * dequant_ptr,uint16_t * eob_ptr,const int16_t * scan,const int16_t * iscan)41 void vp9_quantize_fp_vsx(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
42 const int16_t *round_ptr, const int16_t *quant_ptr,
43 tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr,
44 const int16_t *dequant_ptr, uint16_t *eob_ptr,
45 const int16_t *scan, const int16_t *iscan) {
46 int16x8_t qcoeff0, qcoeff1, dqcoeff0, dqcoeff1, eob;
47 bool16x8_t zero_coeff0, zero_coeff1;
48
49 int16x8_t round = vec_vsx_ld(0, round_ptr);
50 int16x8_t quant = vec_vsx_ld(0, quant_ptr);
51 int16x8_t dequant = vec_vsx_ld(0, dequant_ptr);
52 int16x8_t coeff0 = vec_vsx_ld(0, coeff_ptr);
53 int16x8_t coeff1 = vec_vsx_ld(16, coeff_ptr);
54 int16x8_t scan0 = vec_vsx_ld(0, iscan);
55 int16x8_t scan1 = vec_vsx_ld(16, iscan);
56
57 (void)scan;
58
59 // First set of 8 coeff starts with DC + 7 AC
60 qcoeff0 = vec_mulhi(vec_vaddshs(vec_abs(coeff0), round), quant);
61 zero_coeff0 = vec_cmpeq(qcoeff0, vec_zeros_s16);
62 qcoeff0 = vec_sign(qcoeff0, coeff0);
63 vec_vsx_st(qcoeff0, 0, qcoeff_ptr);
64
65 dqcoeff0 = vec_mladd(qcoeff0, dequant, vec_zeros_s16);
66 vec_vsx_st(dqcoeff0, 0, dqcoeff_ptr);
67
68 // Remove DC value from round and quant
69 round = vec_splat(round, 1);
70 quant = vec_splat(quant, 1);
71
72 // Remove DC value from dequant
73 dequant = vec_splat(dequant, 1);
74
75 // Second set of 8 coeff starts with (all AC)
76 qcoeff1 = vec_mulhi(vec_vaddshs(vec_abs(coeff1), round), quant);
77 zero_coeff1 = vec_cmpeq(qcoeff1, vec_zeros_s16);
78 qcoeff1 = vec_sign(qcoeff1, coeff1);
79 vec_vsx_st(qcoeff1, 16, qcoeff_ptr);
80
81 dqcoeff1 = vec_mladd(qcoeff1, dequant, vec_zeros_s16);
82 vec_vsx_st(dqcoeff1, 16, dqcoeff_ptr);
83
84 eob = vec_max(vec_or(scan0, zero_coeff0), vec_or(scan1, zero_coeff1));
85
86 // We quantize 16 coeff up front (enough for a 4x4) and process 24 coeff per
87 // loop iteration.
88 // for 8x8: 16 + 2 x 24 = 64
89 // for 16x16: 16 + 10 x 24 = 256
90 if (n_coeffs > 16) {
91 int16x8_t coeff2, qcoeff2, dqcoeff2, eob2, scan2;
92 bool16x8_t zero_coeff2;
93
94 int index = 16;
95 int off0 = 32;
96 int off1 = 48;
97 int off2 = 64;
98
99 do {
100 coeff0 = vec_vsx_ld(off0, coeff_ptr);
101 coeff1 = vec_vsx_ld(off1, coeff_ptr);
102 coeff2 = vec_vsx_ld(off2, coeff_ptr);
103 scan0 = vec_vsx_ld(off0, iscan);
104 scan1 = vec_vsx_ld(off1, iscan);
105 scan2 = vec_vsx_ld(off2, iscan);
106
107 qcoeff0 = vec_mulhi(vec_vaddshs(vec_abs(coeff0), round), quant);
108 zero_coeff0 = vec_cmpeq(qcoeff0, vec_zeros_s16);
109 qcoeff0 = vec_sign(qcoeff0, coeff0);
110 vec_vsx_st(qcoeff0, off0, qcoeff_ptr);
111 dqcoeff0 = vec_mladd(qcoeff0, dequant, vec_zeros_s16);
112 vec_vsx_st(dqcoeff0, off0, dqcoeff_ptr);
113
114 qcoeff1 = vec_mulhi(vec_vaddshs(vec_abs(coeff1), round), quant);
115 zero_coeff1 = vec_cmpeq(qcoeff1, vec_zeros_s16);
116 qcoeff1 = vec_sign(qcoeff1, coeff1);
117 vec_vsx_st(qcoeff1, off1, qcoeff_ptr);
118 dqcoeff1 = vec_mladd(qcoeff1, dequant, vec_zeros_s16);
119 vec_vsx_st(dqcoeff1, off1, dqcoeff_ptr);
120
121 qcoeff2 = vec_mulhi(vec_vaddshs(vec_abs(coeff2), round), quant);
122 zero_coeff2 = vec_cmpeq(qcoeff2, vec_zeros_s16);
123 qcoeff2 = vec_sign(qcoeff2, coeff2);
124 vec_vsx_st(qcoeff2, off2, qcoeff_ptr);
125 dqcoeff2 = vec_mladd(qcoeff2, dequant, vec_zeros_s16);
126 vec_vsx_st(dqcoeff2, off2, dqcoeff_ptr);
127
128 eob = vec_max(eob, vec_or(scan0, zero_coeff0));
129 eob2 = vec_max(vec_or(scan1, zero_coeff1), vec_or(scan2, zero_coeff2));
130 eob = vec_max(eob, eob2);
131
132 index += 24;
133 off0 += 48;
134 off1 += 48;
135 off2 += 48;
136 } while (index < n_coeffs);
137 }
138
139 eob = vec_max_across(eob);
140 *eob_ptr = eob[0] + 1;
141 }
142
143 // Sets the value of a 32-bit integers to 1 when the corresponding value in a is
144 // negative.
vec_is_neg(int32x4_t a)145 static INLINE int32x4_t vec_is_neg(int32x4_t a) {
146 return vec_sr(a, vec_shift_sign_s32);
147 }
148
149 // DeQuantization function used for 32x32 blocks. Quantized coeff of 32x32
150 // blocks are twice as big as for other block sizes. As such, using
151 // vec_mladd results in overflow.
dequantize_coeff_32(int16x8_t qcoeff,int16x8_t dequant)152 static INLINE int16x8_t dequantize_coeff_32(int16x8_t qcoeff,
153 int16x8_t dequant) {
154 int32x4_t dqcoeffe = vec_mule(qcoeff, dequant);
155 int32x4_t dqcoeffo = vec_mulo(qcoeff, dequant);
156 // Add 1 if negative to round towards zero because the C uses division.
157 dqcoeffe = vec_add(dqcoeffe, vec_is_neg(dqcoeffe));
158 dqcoeffo = vec_add(dqcoeffo, vec_is_neg(dqcoeffo));
159 dqcoeffe = vec_sra(dqcoeffe, vec_ones_u32);
160 dqcoeffo = vec_sra(dqcoeffo, vec_ones_u32);
161 return (int16x8_t)vec_perm(dqcoeffe, dqcoeffo, vec_perm_odd_even_pack);
162 }
163
vp9_quantize_fp_32x32_vsx(const tran_low_t * coeff_ptr,intptr_t n_coeffs,const int16_t * round_ptr,const int16_t * quant_ptr,tran_low_t * qcoeff_ptr,tran_low_t * dqcoeff_ptr,const int16_t * dequant_ptr,uint16_t * eob_ptr,const int16_t * scan,const int16_t * iscan)164 void vp9_quantize_fp_32x32_vsx(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
165 const int16_t *round_ptr,
166 const int16_t *quant_ptr, tran_low_t *qcoeff_ptr,
167 tran_low_t *dqcoeff_ptr,
168 const int16_t *dequant_ptr, uint16_t *eob_ptr,
169 const int16_t *scan, const int16_t *iscan) {
170 // In stage 1, we quantize 16 coeffs (DC + 15 AC)
171 // In stage 2, we loop 42 times and quantize 24 coeffs per iteration
172 // (32 * 32 - 16) / 24 = 42
173 int num_itr = 42;
174 // Offsets are in bytes, 16 coeffs = 32 bytes
175 int off0 = 32;
176 int off1 = 48;
177 int off2 = 64;
178
179 int16x8_t qcoeff0, qcoeff1, dqcoeff0, dqcoeff1, eob;
180 bool16x8_t mask0, mask1, zero_coeff0, zero_coeff1;
181
182 int16x8_t round = vec_vsx_ld(0, round_ptr);
183 int16x8_t quant = vec_vsx_ld(0, quant_ptr);
184 int16x8_t dequant = vec_vsx_ld(0, dequant_ptr);
185 int16x8_t coeff0 = vec_vsx_ld(0, coeff_ptr);
186 int16x8_t coeff1 = vec_vsx_ld(16, coeff_ptr);
187 int16x8_t scan0 = vec_vsx_ld(0, iscan);
188 int16x8_t scan1 = vec_vsx_ld(16, iscan);
189 int16x8_t thres = vec_sra(dequant, vec_splats((uint16_t)2));
190 int16x8_t abs_coeff0 = vec_abs(coeff0);
191 int16x8_t abs_coeff1 = vec_abs(coeff1);
192
193 (void)scan;
194 (void)n_coeffs;
195
196 mask0 = vec_cmpge(abs_coeff0, thres);
197 round = vec_sra(vec_add(round, vec_ones_s16), vec_ones_u16);
198 // First set of 8 coeff starts with DC + 7 AC
199 qcoeff0 = vec_madds(vec_vaddshs(abs_coeff0, round), quant, vec_zeros_s16);
200 qcoeff0 = vec_and(qcoeff0, mask0);
201 zero_coeff0 = vec_cmpeq(qcoeff0, vec_zeros_s16);
202 qcoeff0 = vec_sign(qcoeff0, coeff0);
203 vec_vsx_st(qcoeff0, 0, qcoeff_ptr);
204
205 dqcoeff0 = dequantize_coeff_32(qcoeff0, dequant);
206 vec_vsx_st(dqcoeff0, 0, dqcoeff_ptr);
207
208 // Remove DC value from thres, round, quant and dequant
209 thres = vec_splat(thres, 1);
210 round = vec_splat(round, 1);
211 quant = vec_splat(quant, 1);
212 dequant = vec_splat(dequant, 1);
213
214 mask1 = vec_cmpge(abs_coeff1, thres);
215
216 // Second set of 8 coeff starts with (all AC)
217 qcoeff1 =
218 vec_madds(vec_vaddshs(vec_abs(coeff1), round), quant, vec_zeros_s16);
219 qcoeff1 = vec_and(qcoeff1, mask1);
220 zero_coeff1 = vec_cmpeq(qcoeff1, vec_zeros_s16);
221 qcoeff1 = vec_sign(qcoeff1, coeff1);
222 vec_vsx_st(qcoeff1, 16, qcoeff_ptr);
223
224 dqcoeff1 = dequantize_coeff_32(qcoeff1, dequant);
225 vec_vsx_st(dqcoeff1, 16, dqcoeff_ptr);
226
227 eob = vec_max(vec_or(scan0, zero_coeff0), vec_or(scan1, zero_coeff1));
228
229 do {
230 int16x8_t coeff2, abs_coeff2, qcoeff2, dqcoeff2, eob2, scan2;
231 bool16x8_t zero_coeff2, mask2;
232 coeff0 = vec_vsx_ld(off0, coeff_ptr);
233 coeff1 = vec_vsx_ld(off1, coeff_ptr);
234 coeff2 = vec_vsx_ld(off2, coeff_ptr);
235 scan0 = vec_vsx_ld(off0, iscan);
236 scan1 = vec_vsx_ld(off1, iscan);
237 scan2 = vec_vsx_ld(off2, iscan);
238
239 abs_coeff0 = vec_abs(coeff0);
240 abs_coeff1 = vec_abs(coeff1);
241 abs_coeff2 = vec_abs(coeff2);
242
243 qcoeff0 = vec_madds(vec_vaddshs(abs_coeff0, round), quant, vec_zeros_s16);
244 qcoeff1 = vec_madds(vec_vaddshs(abs_coeff1, round), quant, vec_zeros_s16);
245 qcoeff2 = vec_madds(vec_vaddshs(abs_coeff2, round), quant, vec_zeros_s16);
246
247 mask0 = vec_cmpge(abs_coeff0, thres);
248 mask1 = vec_cmpge(abs_coeff1, thres);
249 mask2 = vec_cmpge(abs_coeff2, thres);
250
251 qcoeff0 = vec_and(qcoeff0, mask0);
252 qcoeff1 = vec_and(qcoeff1, mask1);
253 qcoeff2 = vec_and(qcoeff2, mask2);
254
255 zero_coeff0 = vec_cmpeq(qcoeff0, vec_zeros_s16);
256 zero_coeff1 = vec_cmpeq(qcoeff1, vec_zeros_s16);
257 zero_coeff2 = vec_cmpeq(qcoeff2, vec_zeros_s16);
258
259 qcoeff0 = vec_sign(qcoeff0, coeff0);
260 qcoeff1 = vec_sign(qcoeff1, coeff1);
261 qcoeff2 = vec_sign(qcoeff2, coeff2);
262
263 vec_vsx_st(qcoeff0, off0, qcoeff_ptr);
264 vec_vsx_st(qcoeff1, off1, qcoeff_ptr);
265 vec_vsx_st(qcoeff2, off2, qcoeff_ptr);
266
267 dqcoeff0 = dequantize_coeff_32(qcoeff0, dequant);
268 dqcoeff1 = dequantize_coeff_32(qcoeff1, dequant);
269 dqcoeff2 = dequantize_coeff_32(qcoeff2, dequant);
270
271 vec_vsx_st(dqcoeff0, off0, dqcoeff_ptr);
272 vec_vsx_st(dqcoeff1, off1, dqcoeff_ptr);
273 vec_vsx_st(dqcoeff2, off2, dqcoeff_ptr);
274
275 eob = vec_max(eob, vec_or(scan0, zero_coeff0));
276 eob2 = vec_max(vec_or(scan1, zero_coeff1), vec_or(scan2, zero_coeff2));
277 eob = vec_max(eob, eob2);
278
279 off0 += 48;
280 off1 += 48;
281 off2 += 48;
282 num_itr--;
283 } while (num_itr != 0);
284
285 eob = vec_max_across(eob);
286 *eob_ptr = eob[0] + 1;
287 }
288