Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. }
  272.