OSDN Git Service

intel-vaapi-driver 1.8.1.pre1
[android-x86/hardware-intel-common-vaapi.git] / src / i965_vpp_avs.c
1 /*
2  * i965_vpp_avs.c - Adaptive Video Scaler (AVS) block
3  *
4  * Copyright (C) 2014 Intel Corporation
5  *   Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 #include "sysdeps.h"
29 #include <math.h>
30 #include <va/va.h>
31 #include "i965_vpp_avs.h"
32
33 typedef void (*AVSGenCoeffsFunc)(float *coeffs, int num_coeffs, int phase,
34     int num_phases, float f);
35
36 /* Initializes all coefficients to zero */
37 static void
38 avs_init_coeffs(float *coeffs, int num_coeffs)
39 {
40 #if defined(__STDC_IEC_559__) && (__STDC_IEC_559__ > 0)
41     memset(coeffs, 0, num_coeffs * sizeof(*coeffs));
42 #else
43     int i;
44
45     for (i = 0; i < num_coeffs; i++)
46         coeffs[i] = 0.0f;
47 #endif
48 }
49
50 /* Computes the sinc(x) function */
51 static float
52 avs_sinc(float x)
53 {
54     if (x == 0.0f)
55         return 1.0f;
56     return sin(x * M_PI) / (x * M_PI);
57 }
58
59 /* Convolution kernel for linear interpolation */
60 static float
61 avs_kernel_linear(float x)
62 {
63     const float abs_x = fabsf(x);
64
65     return abs_x < 1.0f ? 1 - abs_x : 0.0f;
66 }
67
68 /* Convolution kernel for Lanczos-based interpolation */
69 static float
70 avs_kernel_lanczos(float x, float a)
71 {
72     const float abs_x = fabsf(x);
73
74     return abs_x < a ? avs_sinc(x) * avs_sinc(x / a) : 0.0f;
75 }
76
77 /* Truncates floating-point value towards an epsilon factor */
78 static inline float
79 avs_trunc_coeff(float x, float epsilon)
80 {
81     return rintf(x / epsilon) * epsilon;
82 }
83
84 /* Normalize coefficients for one sample/direction */
85 static void
86 avs_normalize_coeffs_1(float *coeffs, int num_coeffs, float epsilon)
87 {
88     float s, sum = 0.0;
89     int i, c, r, r1;
90
91     for (i = 0; i < num_coeffs; i++)
92         sum += coeffs[i];
93
94     if (sum < epsilon)
95         return;
96
97     s = 0.0;
98     for (i = 0; i < num_coeffs; i++)
99         s += (coeffs[i] = avs_trunc_coeff(coeffs[i] / sum, epsilon));
100
101     /* Distribute the remaining bits, while allocating more to the center */
102     c = num_coeffs/2;
103     c = c - (coeffs[c - 1] > coeffs[c]);
104
105     r = (1.0f - s) / epsilon;
106     r1 = r / 4;
107     if (coeffs[c + 1] == 0.0f)
108         coeffs[c] += r * epsilon;
109     else {
110         coeffs[c] += (r - 2*r1) * epsilon;
111         coeffs[c - 1] += r1 * epsilon;
112         coeffs[c + 1] += r1 * epsilon;
113     }
114 }
115
116 /* Normalize all coefficients so that their sum yields 1.0f */
117 static void
118 avs_normalize_coeffs(AVSCoeffs *coeffs, const AVSConfig *config)
119 {
120     avs_normalize_coeffs_1(coeffs->y_k_h, config->num_luma_coeffs,
121         config->coeff_epsilon);
122     avs_normalize_coeffs_1(coeffs->y_k_v, config->num_luma_coeffs,
123         config->coeff_epsilon);
124     avs_normalize_coeffs_1(coeffs->uv_k_h, config->num_chroma_coeffs,
125         config->coeff_epsilon);
126     avs_normalize_coeffs_1(coeffs->uv_k_v, config->num_chroma_coeffs,
127         config->coeff_epsilon);
128 }
129
130 /* Validate coefficients for one sample/direction */
131 static bool
132 avs_validate_coeffs_1(float *coeffs, int num_coeffs, const float *min_coeffs,
133     const float *max_coeffs)
134 {
135     int i;
136
137     for (i = 0; i < num_coeffs; i++) {
138         if (coeffs[i] < min_coeffs[i] || coeffs[i] > max_coeffs[i])
139             return false;
140     }
141     return true;
142 }
143
144 /* Validate coefficients wrt. the supplied range in config */
145 static bool
146 avs_validate_coeffs(AVSCoeffs *coeffs, const AVSConfig *config)
147 {
148     const AVSCoeffs * const min_coeffs = &config->coeff_range.lower_bound;
149     const AVSCoeffs * const max_coeffs = &config->coeff_range.upper_bound;
150
151     return avs_validate_coeffs_1(coeffs->y_k_h, config->num_luma_coeffs,
152             min_coeffs->y_k_h, max_coeffs->y_k_h) &&
153         avs_validate_coeffs_1(coeffs->y_k_v, config->num_luma_coeffs,
154             min_coeffs->y_k_v, max_coeffs->y_k_v) &&
155         avs_validate_coeffs_1(coeffs->uv_k_h, config->num_chroma_coeffs,
156             min_coeffs->uv_k_h, max_coeffs->uv_k_h) &&
157         avs_validate_coeffs_1(coeffs->uv_k_v, config->num_chroma_coeffs,
158             min_coeffs->uv_k_v, max_coeffs->uv_k_v);
159 }
160
161 /* Generate coefficients for default quality (bilinear) */
162 static void
163 avs_gen_coeffs_linear(float *coeffs, int num_coeffs, int phase, int num_phases,
164     float f)
165 {
166     const int c = num_coeffs/2 - 1;
167     const float p = (float)phase / (num_phases*2);
168
169     avs_init_coeffs(coeffs, num_coeffs);
170     coeffs[c] = avs_kernel_linear(p);
171     coeffs[c + 1] = avs_kernel_linear(p - 1);
172 }
173
174 /* Generate coefficients for high quality (lanczos) */
175 static void
176 avs_gen_coeffs_lanczos(float *coeffs, int num_coeffs, int phase, int num_phases,
177     float f)
178 {
179     const int c = num_coeffs/2 - 1;
180     const int l = num_coeffs > 4 ? 3 : 2;
181     const float p = (float)phase / (num_phases*2);
182     int i;
183
184     if (f > 1.0f)
185         f = 1.0f;
186     for (i = 0; i < num_coeffs; i++)
187         coeffs[i] = avs_kernel_lanczos((i - (c + p)) * f, l);
188 }
189
190 /* Generate coefficients with the supplied scaler */
191 static bool
192 avs_gen_coeffs(AVSState *avs, float sx, float sy, AVSGenCoeffsFunc gen_coeffs)
193 {
194     const AVSConfig * const config = avs->config;
195     int i;
196
197     for (i = 0; i <= config->num_phases; i++) {
198         AVSCoeffs * const coeffs = &avs->coeffs[i];
199
200         gen_coeffs(coeffs->y_k_h, config->num_luma_coeffs,
201             i, config->num_phases, sx);
202         gen_coeffs(coeffs->uv_k_h, config->num_chroma_coeffs,
203             i, config->num_phases, sx);
204         gen_coeffs(coeffs->y_k_v, config->num_luma_coeffs,
205             i, config->num_phases, sy);
206         gen_coeffs(coeffs->uv_k_v, config->num_chroma_coeffs,
207             i, config->num_phases, sy);
208
209         avs_normalize_coeffs(coeffs, config);
210         if (!avs_validate_coeffs(coeffs, config))
211             return false;
212     }
213     return true;
214 }
215
216 /* Initializes AVS state with the supplied configuration */
217 void
218 avs_init_state(AVSState *avs, const AVSConfig *config)
219 {
220     avs->config = config;
221     avs->flags = 0;
222     avs->scale_x = 0.0f;
223     avs->scale_y = 0.0f;
224 }
225
226 /* Checks whether the AVS scaling parameters changed */
227 static inline bool
228 avs_params_changed(AVSState *avs, float sx, float sy, uint32_t flags)
229 {
230     if (avs->flags != flags)
231         return true;
232
233     if (flags >= VA_FILTER_SCALING_HQ) {
234         if (avs->scale_x != sx || avs->scale_y != sy)
235             return true;
236     }
237     else {
238         if (avs->scale_x == 0.0f || avs->scale_y == 0.0f)
239             return true;
240     }
241     return false;
242 }
243
244 /* Updates AVS coefficients for the supplied factors and quality level */
245 bool
246 avs_update_coefficients(AVSState *avs, float sx, float sy, uint32_t flags)
247 {
248     AVSGenCoeffsFunc gen_coeffs;
249
250     flags &= VA_FILTER_SCALING_MASK;
251     if (!avs_params_changed(avs, sx, sy, flags))
252         return true;
253
254     switch (flags) {
255     case VA_FILTER_SCALING_HQ:
256         gen_coeffs = avs_gen_coeffs_lanczos;
257         break;
258     default:
259         gen_coeffs = avs_gen_coeffs_linear;
260         break;
261     }
262     if (!avs_gen_coeffs(avs, sx, sy, gen_coeffs)) {
263         assert(0 && "invalid set of coefficients generated");
264         return false;
265     }
266
267     avs->flags = flags;
268     avs->scale_x = sx;
269     avs->scale_y = sy;
270     return true;
271 }