2 * i965_vpp_avs.c - Adaptive Video Scaler (AVS) block
4 * Copyright (C) 2014 Intel Corporation
5 * Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
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:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
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.
31 #include "i965_vpp_avs.h"
33 typedef void (*AVSGenCoeffsFunc)(float *coeffs, int num_coeffs, int phase,
34 int num_phases, float f);
36 /* Initializes all coefficients to zero */
38 avs_init_coeffs(float *coeffs, int num_coeffs)
40 #if defined(__STDC_IEC_559__) && (__STDC_IEC_559__ > 0)
41 memset(coeffs, 0, num_coeffs * sizeof(*coeffs));
45 for (i = 0; i < num_coeffs; i++)
50 /* Computes the sinc(x) function */
56 return sin(x * M_PI) / (x * M_PI);
59 /* Convolution kernel for linear interpolation */
61 avs_kernel_linear(float x)
63 const float abs_x = fabsf(x);
65 return abs_x < 1.0f ? 1 - abs_x : 0.0f;
68 /* Convolution kernel for Lanczos-based interpolation */
70 avs_kernel_lanczos(float x, float a)
72 const float abs_x = fabsf(x);
74 return abs_x < a ? avs_sinc(x) * avs_sinc(x / a) : 0.0f;
77 /* Truncates floating-point value towards an epsilon factor */
79 avs_trunc_coeff(float x, float epsilon)
81 return rintf(x / epsilon) * epsilon;
84 /* Normalize coefficients for one sample/direction */
86 avs_normalize_coeffs_1(float *coeffs, int num_coeffs, float epsilon)
91 for (i = 0; i < num_coeffs; i++)
98 for (i = 0; i < num_coeffs; i++)
99 s += (coeffs[i] = avs_trunc_coeff(coeffs[i] / sum, epsilon));
101 /* Distribute the remaining bits, while allocating more to the center */
103 c = c - (coeffs[c - 1] > coeffs[c]);
105 r = (1.0f - s) / epsilon;
107 if (coeffs[c + 1] == 0.0f)
108 coeffs[c] += r * epsilon;
110 coeffs[c] += (r - 2*r1) * epsilon;
111 coeffs[c - 1] += r1 * epsilon;
112 coeffs[c + 1] += r1 * epsilon;
116 /* Normalize all coefficients so that their sum yields 1.0f */
118 avs_normalize_coeffs(AVSCoeffs *coeffs, const AVSConfig *config)
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);
130 /* Validate coefficients for one sample/direction */
132 avs_validate_coeffs_1(float *coeffs, int num_coeffs, const float *min_coeffs,
133 const float *max_coeffs)
137 for (i = 0; i < num_coeffs; i++) {
138 if (coeffs[i] < min_coeffs[i] || coeffs[i] > max_coeffs[i])
144 /* Validate coefficients wrt. the supplied range in config */
146 avs_validate_coeffs(AVSCoeffs *coeffs, const AVSConfig *config)
148 const AVSCoeffs * const min_coeffs = &config->coeff_range.lower_bound;
149 const AVSCoeffs * const max_coeffs = &config->coeff_range.upper_bound;
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);
161 /* Generate coefficients for default quality (bilinear) */
163 avs_gen_coeffs_linear(float *coeffs, int num_coeffs, int phase, int num_phases,
166 const int c = num_coeffs/2 - 1;
167 const float p = (float)phase / (num_phases*2);
169 avs_init_coeffs(coeffs, num_coeffs);
170 coeffs[c] = avs_kernel_linear(p);
171 coeffs[c + 1] = avs_kernel_linear(p - 1);
174 /* Generate coefficients for high quality (lanczos) */
176 avs_gen_coeffs_lanczos(float *coeffs, int num_coeffs, int phase, int num_phases,
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);
186 for (i = 0; i < num_coeffs; i++)
187 coeffs[i] = avs_kernel_lanczos((i - (c + p)) * f, l);
190 /* Generate coefficients with the supplied scaler */
192 avs_gen_coeffs(AVSState *avs, float sx, float sy, AVSGenCoeffsFunc gen_coeffs)
194 const AVSConfig * const config = avs->config;
197 for (i = 0; i <= config->num_phases; i++) {
198 AVSCoeffs * const coeffs = &avs->coeffs[i];
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);
209 avs_normalize_coeffs(coeffs, config);
210 if (!avs_validate_coeffs(coeffs, config))
216 /* Initializes AVS state with the supplied configuration */
218 avs_init_state(AVSState *avs, const AVSConfig *config)
220 avs->config = config;
226 /* Checks whether the AVS scaling parameters changed */
228 avs_params_changed(AVSState *avs, float sx, float sy, uint32_t flags)
230 if (avs->flags != flags)
233 if (flags >= VA_FILTER_SCALING_HQ) {
234 if (avs->scale_x != sx || avs->scale_y != sy)
238 if (avs->scale_x == 0.0f || avs->scale_y == 0.0f)
244 /* Updates AVS coefficients for the supplied factors and quality level */
246 avs_update_coefficients(AVSState *avs, float sx, float sy, uint32_t flags)
248 AVSGenCoeffsFunc gen_coeffs;
250 flags &= VA_FILTER_SCALING_MASK;
251 if (!avs_params_changed(avs, sx, sy, flags))
255 case VA_FILTER_SCALING_HQ:
256 gen_coeffs = avs_gen_coeffs_lanczos;
259 gen_coeffs = avs_gen_coeffs_linear;
262 if (!avs_gen_coeffs(avs, sx, sy, gen_coeffs)) {
263 assert(0 && "invalid set of coefficients generated");