]> granicus.if.org Git - libvpx/blob - vpx_dsp/fwd_txfm.c
Factor forward 2D-DCT transforms into vpx_dsp
[libvpx] / vpx_dsp / fwd_txfm.c
1 /*
2  *  Copyright (c) 2015 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_dsp/fwd_txfm.h"
12
13 void vp9_fdct4x4_c(const int16_t *input, tran_low_t *output, int stride) {
14   // The 2D transform is done with two passes which are actually pretty
15   // similar. In the first one, we transform the columns and transpose
16   // the results. In the second one, we transform the rows. To achieve that,
17   // as the first pass results are transposed, we transpose the columns (that
18   // is the transposed rows) and transpose the results (so that it goes back
19   // in normal/row positions).
20   int pass;
21   // We need an intermediate buffer between passes.
22   tran_low_t intermediate[4 * 4];
23   const int16_t *in_pass0 = input;
24   const tran_low_t *in = NULL;
25   tran_low_t *out = intermediate;
26   // Do the two transform/transpose passes
27   for (pass = 0; pass < 2; ++pass) {
28     tran_high_t input[4];      // canbe16
29     tran_high_t step[4];       // canbe16
30     tran_high_t temp1, temp2;  // needs32
31     int i;
32     for (i = 0; i < 4; ++i) {
33       // Load inputs.
34       if (0 == pass) {
35         input[0] = in_pass0[0 * stride] * 16;
36         input[1] = in_pass0[1 * stride] * 16;
37         input[2] = in_pass0[2 * stride] * 16;
38         input[3] = in_pass0[3 * stride] * 16;
39         if (i == 0 && input[0]) {
40           input[0] += 1;
41         }
42       } else {
43         input[0] = in[0 * 4];
44         input[1] = in[1 * 4];
45         input[2] = in[2 * 4];
46         input[3] = in[3 * 4];
47       }
48       // Transform.
49       step[0] = input[0] + input[3];
50       step[1] = input[1] + input[2];
51       step[2] = input[1] - input[2];
52       step[3] = input[0] - input[3];
53       temp1 = (step[0] + step[1]) * cospi_16_64;
54       temp2 = (step[0] - step[1]) * cospi_16_64;
55       out[0] = (tran_low_t)fdct_round_shift(temp1);
56       out[2] = (tran_low_t)fdct_round_shift(temp2);
57       temp1 = step[2] * cospi_24_64 + step[3] * cospi_8_64;
58       temp2 = -step[2] * cospi_8_64 + step[3] * cospi_24_64;
59       out[1] = (tran_low_t)fdct_round_shift(temp1);
60       out[3] = (tran_low_t)fdct_round_shift(temp2);
61       // Do next column (which is a transposed row in second/horizontal pass)
62       in_pass0++;
63       in++;
64       out += 4;
65     }
66     // Setup in/out for next pass.
67     in = intermediate;
68     out = output;
69   }
70
71   {
72     int i, j;
73     for (i = 0; i < 4; ++i) {
74       for (j = 0; j < 4; ++j)
75         output[j + i * 4] = (output[j + i * 4] + 1) >> 2;
76     }
77   }
78 }
79
80 void vp9_fdct8x8_c(const int16_t *input, tran_low_t *final_output, int stride) {
81   int i, j;
82   tran_low_t intermediate[64];
83   int pass;
84   tran_low_t *output = intermediate;
85   const tran_low_t *in = NULL;
86
87   // Transform columns
88   for (pass = 0; pass < 2; ++pass) {
89     tran_high_t s0, s1, s2, s3, s4, s5, s6, s7;  // canbe16
90     tran_high_t t0, t1, t2, t3;                  // needs32
91     tran_high_t x0, x1, x2, x3;                  // canbe16
92
93     int i;
94     for (i = 0; i < 8; i++) {
95       // stage 1
96       if (pass == 0) {
97         s0 = (input[0 * stride] + input[7 * stride]) * 4;
98         s1 = (input[1 * stride] + input[6 * stride]) * 4;
99         s2 = (input[2 * stride] + input[5 * stride]) * 4;
100         s3 = (input[3 * stride] + input[4 * stride]) * 4;
101         s4 = (input[3 * stride] - input[4 * stride]) * 4;
102         s5 = (input[2 * stride] - input[5 * stride]) * 4;
103         s6 = (input[1 * stride] - input[6 * stride]) * 4;
104         s7 = (input[0 * stride] - input[7 * stride]) * 4;
105         ++input;
106       } else {
107         s0 = in[0 * 8] + in[7 * 8];
108         s1 = in[1 * 8] + in[6 * 8];
109         s2 = in[2 * 8] + in[5 * 8];
110         s3 = in[3 * 8] + in[4 * 8];
111         s4 = in[3 * 8] - in[4 * 8];
112         s5 = in[2 * 8] - in[5 * 8];
113         s6 = in[1 * 8] - in[6 * 8];
114         s7 = in[0 * 8] - in[7 * 8];
115         ++in;
116       }
117
118       // fdct4(step, step);
119       x0 = s0 + s3;
120       x1 = s1 + s2;
121       x2 = s1 - s2;
122       x3 = s0 - s3;
123       t0 = (x0 + x1) * cospi_16_64;
124       t1 = (x0 - x1) * cospi_16_64;
125       t2 =  x2 * cospi_24_64 + x3 *  cospi_8_64;
126       t3 = -x2 * cospi_8_64  + x3 * cospi_24_64;
127       output[0] = (tran_low_t)fdct_round_shift(t0);
128       output[2] = (tran_low_t)fdct_round_shift(t2);
129       output[4] = (tran_low_t)fdct_round_shift(t1);
130       output[6] = (tran_low_t)fdct_round_shift(t3);
131
132       // Stage 2
133       t0 = (s6 - s5) * cospi_16_64;
134       t1 = (s6 + s5) * cospi_16_64;
135       t2 = fdct_round_shift(t0);
136       t3 = fdct_round_shift(t1);
137
138       // Stage 3
139       x0 = s4 + t2;
140       x1 = s4 - t2;
141       x2 = s7 - t3;
142       x3 = s7 + t3;
143
144       // Stage 4
145       t0 = x0 * cospi_28_64 + x3 *   cospi_4_64;
146       t1 = x1 * cospi_12_64 + x2 *  cospi_20_64;
147       t2 = x2 * cospi_12_64 + x1 * -cospi_20_64;
148       t3 = x3 * cospi_28_64 + x0 *  -cospi_4_64;
149       output[1] = (tran_low_t)fdct_round_shift(t0);
150       output[3] = (tran_low_t)fdct_round_shift(t2);
151       output[5] = (tran_low_t)fdct_round_shift(t1);
152       output[7] = (tran_low_t)fdct_round_shift(t3);
153       output += 8;
154     }
155     in  = intermediate;
156     output = final_output;
157   }
158
159   // Rows
160   for (i = 0; i < 8; ++i) {
161     for (j = 0; j < 8; ++j)
162       final_output[j + i * 8] /= 2;
163   }
164 }
165
166 void vp9_fdct16x16_c(const int16_t *input, tran_low_t *output, int stride) {
167   // The 2D transform is done with two passes which are actually pretty
168   // similar. In the first one, we transform the columns and transpose
169   // the results. In the second one, we transform the rows. To achieve that,
170   // as the first pass results are transposed, we transpose the columns (that
171   // is the transposed rows) and transpose the results (so that it goes back
172   // in normal/row positions).
173   int pass;
174   // We need an intermediate buffer between passes.
175   tran_low_t intermediate[256];
176   const int16_t *in_pass0 = input;
177   const tran_low_t *in = NULL;
178   tran_low_t *out = intermediate;
179   // Do the two transform/transpose passes
180   for (pass = 0; pass < 2; ++pass) {
181     tran_high_t step1[8];      // canbe16
182     tran_high_t step2[8];      // canbe16
183     tran_high_t step3[8];      // canbe16
184     tran_high_t input[8];      // canbe16
185     tran_high_t temp1, temp2;  // needs32
186     int i;
187     for (i = 0; i < 16; i++) {
188       if (0 == pass) {
189         // Calculate input for the first 8 results.
190         input[0] = (in_pass0[0 * stride] + in_pass0[15 * stride]) * 4;
191         input[1] = (in_pass0[1 * stride] + in_pass0[14 * stride]) * 4;
192         input[2] = (in_pass0[2 * stride] + in_pass0[13 * stride]) * 4;
193         input[3] = (in_pass0[3 * stride] + in_pass0[12 * stride]) * 4;
194         input[4] = (in_pass0[4 * stride] + in_pass0[11 * stride]) * 4;
195         input[5] = (in_pass0[5 * stride] + in_pass0[10 * stride]) * 4;
196         input[6] = (in_pass0[6 * stride] + in_pass0[ 9 * stride]) * 4;
197         input[7] = (in_pass0[7 * stride] + in_pass0[ 8 * stride]) * 4;
198         // Calculate input for the next 8 results.
199         step1[0] = (in_pass0[7 * stride] - in_pass0[ 8 * stride]) * 4;
200         step1[1] = (in_pass0[6 * stride] - in_pass0[ 9 * stride]) * 4;
201         step1[2] = (in_pass0[5 * stride] - in_pass0[10 * stride]) * 4;
202         step1[3] = (in_pass0[4 * stride] - in_pass0[11 * stride]) * 4;
203         step1[4] = (in_pass0[3 * stride] - in_pass0[12 * stride]) * 4;
204         step1[5] = (in_pass0[2 * stride] - in_pass0[13 * stride]) * 4;
205         step1[6] = (in_pass0[1 * stride] - in_pass0[14 * stride]) * 4;
206         step1[7] = (in_pass0[0 * stride] - in_pass0[15 * stride]) * 4;
207       } else {
208         // Calculate input for the first 8 results.
209         input[0] = ((in[0 * 16] + 1) >> 2) + ((in[15 * 16] + 1) >> 2);
210         input[1] = ((in[1 * 16] + 1) >> 2) + ((in[14 * 16] + 1) >> 2);
211         input[2] = ((in[2 * 16] + 1) >> 2) + ((in[13 * 16] + 1) >> 2);
212         input[3] = ((in[3 * 16] + 1) >> 2) + ((in[12 * 16] + 1) >> 2);
213         input[4] = ((in[4 * 16] + 1) >> 2) + ((in[11 * 16] + 1) >> 2);
214         input[5] = ((in[5 * 16] + 1) >> 2) + ((in[10 * 16] + 1) >> 2);
215         input[6] = ((in[6 * 16] + 1) >> 2) + ((in[ 9 * 16] + 1) >> 2);
216         input[7] = ((in[7 * 16] + 1) >> 2) + ((in[ 8 * 16] + 1) >> 2);
217         // Calculate input for the next 8 results.
218         step1[0] = ((in[7 * 16] + 1) >> 2) - ((in[ 8 * 16] + 1) >> 2);
219         step1[1] = ((in[6 * 16] + 1) >> 2) - ((in[ 9 * 16] + 1) >> 2);
220         step1[2] = ((in[5 * 16] + 1) >> 2) - ((in[10 * 16] + 1) >> 2);
221         step1[3] = ((in[4 * 16] + 1) >> 2) - ((in[11 * 16] + 1) >> 2);
222         step1[4] = ((in[3 * 16] + 1) >> 2) - ((in[12 * 16] + 1) >> 2);
223         step1[5] = ((in[2 * 16] + 1) >> 2) - ((in[13 * 16] + 1) >> 2);
224         step1[6] = ((in[1 * 16] + 1) >> 2) - ((in[14 * 16] + 1) >> 2);
225         step1[7] = ((in[0 * 16] + 1) >> 2) - ((in[15 * 16] + 1) >> 2);
226       }
227       // Work on the first eight values; fdct8(input, even_results);
228       {
229         tran_high_t s0, s1, s2, s3, s4, s5, s6, s7;  // canbe16
230         tran_high_t t0, t1, t2, t3;                  // needs32
231         tran_high_t x0, x1, x2, x3;                  // canbe16
232
233         // stage 1
234         s0 = input[0] + input[7];
235         s1 = input[1] + input[6];
236         s2 = input[2] + input[5];
237         s3 = input[3] + input[4];
238         s4 = input[3] - input[4];
239         s5 = input[2] - input[5];
240         s6 = input[1] - input[6];
241         s7 = input[0] - input[7];
242
243         // fdct4(step, step);
244         x0 = s0 + s3;
245         x1 = s1 + s2;
246         x2 = s1 - s2;
247         x3 = s0 - s3;
248         t0 = (x0 + x1) * cospi_16_64;
249         t1 = (x0 - x1) * cospi_16_64;
250         t2 = x3 * cospi_8_64  + x2 * cospi_24_64;
251         t3 = x3 * cospi_24_64 - x2 * cospi_8_64;
252         out[0] = (tran_low_t)fdct_round_shift(t0);
253         out[4] = (tran_low_t)fdct_round_shift(t2);
254         out[8] = (tran_low_t)fdct_round_shift(t1);
255         out[12] = (tran_low_t)fdct_round_shift(t3);
256
257         // Stage 2
258         t0 = (s6 - s5) * cospi_16_64;
259         t1 = (s6 + s5) * cospi_16_64;
260         t2 = fdct_round_shift(t0);
261         t3 = fdct_round_shift(t1);
262
263         // Stage 3
264         x0 = s4 + t2;
265         x1 = s4 - t2;
266         x2 = s7 - t3;
267         x3 = s7 + t3;
268
269         // Stage 4
270         t0 = x0 * cospi_28_64 + x3 *   cospi_4_64;
271         t1 = x1 * cospi_12_64 + x2 *  cospi_20_64;
272         t2 = x2 * cospi_12_64 + x1 * -cospi_20_64;
273         t3 = x3 * cospi_28_64 + x0 *  -cospi_4_64;
274         out[2] = (tran_low_t)fdct_round_shift(t0);
275         out[6] = (tran_low_t)fdct_round_shift(t2);
276         out[10] = (tran_low_t)fdct_round_shift(t1);
277         out[14] = (tran_low_t)fdct_round_shift(t3);
278       }
279       // Work on the next eight values; step1 -> odd_results
280       {
281         // step 2
282         temp1 = (step1[5] - step1[2]) * cospi_16_64;
283         temp2 = (step1[4] - step1[3]) * cospi_16_64;
284         step2[2] = fdct_round_shift(temp1);
285         step2[3] = fdct_round_shift(temp2);
286         temp1 = (step1[4] + step1[3]) * cospi_16_64;
287         temp2 = (step1[5] + step1[2]) * cospi_16_64;
288         step2[4] = fdct_round_shift(temp1);
289         step2[5] = fdct_round_shift(temp2);
290         // step 3
291         step3[0] = step1[0] + step2[3];
292         step3[1] = step1[1] + step2[2];
293         step3[2] = step1[1] - step2[2];
294         step3[3] = step1[0] - step2[3];
295         step3[4] = step1[7] - step2[4];
296         step3[5] = step1[6] - step2[5];
297         step3[6] = step1[6] + step2[5];
298         step3[7] = step1[7] + step2[4];
299         // step 4
300         temp1 = step3[1] *  -cospi_8_64 + step3[6] * cospi_24_64;
301         temp2 = step3[2] * cospi_24_64 + step3[5] *  cospi_8_64;
302         step2[1] = fdct_round_shift(temp1);
303         step2[2] = fdct_round_shift(temp2);
304         temp1 = step3[2] * cospi_8_64 - step3[5] * cospi_24_64;
305         temp2 = step3[1] * cospi_24_64 + step3[6] *  cospi_8_64;
306         step2[5] = fdct_round_shift(temp1);
307         step2[6] = fdct_round_shift(temp2);
308         // step 5
309         step1[0] = step3[0] + step2[1];
310         step1[1] = step3[0] - step2[1];
311         step1[2] = step3[3] + step2[2];
312         step1[3] = step3[3] - step2[2];
313         step1[4] = step3[4] - step2[5];
314         step1[5] = step3[4] + step2[5];
315         step1[6] = step3[7] - step2[6];
316         step1[7] = step3[7] + step2[6];
317         // step 6
318         temp1 = step1[0] * cospi_30_64 + step1[7] *  cospi_2_64;
319         temp2 = step1[1] * cospi_14_64 + step1[6] * cospi_18_64;
320         out[1] = (tran_low_t)fdct_round_shift(temp1);
321         out[9] = (tran_low_t)fdct_round_shift(temp2);
322         temp1 = step1[2] * cospi_22_64 + step1[5] * cospi_10_64;
323         temp2 = step1[3] *  cospi_6_64 + step1[4] * cospi_26_64;
324         out[5] = (tran_low_t)fdct_round_shift(temp1);
325         out[13] = (tran_low_t)fdct_round_shift(temp2);
326         temp1 = step1[3] * -cospi_26_64 + step1[4] *  cospi_6_64;
327         temp2 = step1[2] * -cospi_10_64 + step1[5] * cospi_22_64;
328         out[3] = (tran_low_t)fdct_round_shift(temp1);
329         out[11] = (tran_low_t)fdct_round_shift(temp2);
330         temp1 = step1[1] * -cospi_18_64 + step1[6] * cospi_14_64;
331         temp2 = step1[0] *  -cospi_2_64 + step1[7] * cospi_30_64;
332         out[7] = (tran_low_t)fdct_round_shift(temp1);
333         out[15] = (tran_low_t)fdct_round_shift(temp2);
334       }
335       // Do next column (which is a transposed row in second/horizontal pass)
336       in++;
337       in_pass0++;
338       out += 16;
339     }
340     // Setup in/out for next pass.
341     in = intermediate;
342     out = output;
343   }
344 }
345
346 #if CONFIG_VP9_HIGHBITDEPTH
347 void vp9_highbd_fdct4x4_c(const int16_t *input, tran_low_t *output,
348                           int stride) {
349   vp9_fdct4x4_c(input, output, stride);
350 }
351
352 void vp9_highbd_fdct8x8_c(const int16_t *input, tran_low_t *final_output,
353                           int stride) {
354   vp9_fdct8x8_c(input, final_output, stride);
355 }
356
357 void vp9_highbd_fdct16x16_c(const int16_t *input, tran_low_t *output,
358                             int stride) {
359   vp9_fdct16x16_c(input, output, stride);
360 }
361 #endif  // CONFIG_VP9_HIGHBITDEPTH