linux/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c
<<
>>
Prefs
   1/*
   2 * Support for Intel Camera Imaging ISP subsystem.
   3 * Copyright (c) 2015, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 */
  14
  15#include <linux/slab.h>
  16
  17#include <math_support.h>
  18#include "sh_css_param_shading.h"
  19#include "ia_css_shading.h"
  20#include "assert_support.h"
  21#include "sh_css_defs.h"
  22#include "sh_css_internal.h"
  23#include "ia_css_debug.h"
  24#include "ia_css_pipe_binarydesc.h"
  25
  26#include "sh_css_hrt.h"
  27
  28#include "platform_support.h"
  29
  30/* Bilinear interpolation on shading tables:
  31 * For each target point T, we calculate the 4 surrounding source points:
  32 * ul (upper left), ur (upper right), ll (lower left) and lr (lower right).
  33 * We then calculate the distances from the T to the source points: x0, x1,
  34 * y0 and y1.
  35 * We then calculate the value of T:
  36 *   dx0*dy0*Slr + dx0*dy1*Sur + dx1*dy0*Sll + dx1*dy1*Sul.
  37 * We choose a grid size of 1x1 which means:
  38 *   dx1 = 1-dx0
  39 *   dy1 = 1-dy0
  40 *
  41 *   Sul dx0         dx1      Sur
  42 *    .<----->|<------------->.
  43 *    ^
  44 * dy0|
  45 *    v        T
  46 *    -        .
  47 *    ^
  48 *    |
  49 * dy1|
  50 *    v
  51 *    .                        .
  52 *   Sll                      Slr
  53 *
  54 * Padding:
  55 * The area that the ISP operates on can include padding both on the left
  56 * and the right. We need to padd the shading table such that the shading
  57 * values end up on the correct pixel values. This means we must padd the
  58 * shading table to match the ISP padding.
  59 * We can have 5 cases:
  60 * 1. All 4 points fall in the left padding.
  61 * 2. The left 2 points fall in the left padding.
  62 * 3. All 4 points fall in the cropped (target) region.
  63 * 4. The right 2 points fall in the right padding.
  64 * 5. All 4 points fall in the right padding.
  65 * Cases 1 and 5 are easy to handle: we simply use the
  66 * value 1 in the shading table.
  67 * Cases 2 and 4 require interpolation that takes into
  68 * account how far into the padding area the pixels
  69 * fall. We extrapolate the shading table into the
  70 * padded area and then interpolate.
  71 */
  72static void
  73crop_and_interpolate(unsigned int cropped_width,
  74                     unsigned int cropped_height,
  75                     unsigned int left_padding,
  76                     int right_padding,
  77                     int top_padding,
  78                     const struct ia_css_shading_table *in_table,
  79                     struct ia_css_shading_table *out_table,
  80                     enum ia_css_sc_color color)
  81{
  82        unsigned int i, j,
  83                     sensor_width,
  84                     sensor_height,
  85                     table_width,
  86                     table_height,
  87                     table_cell_h,
  88                     out_cell_size,
  89                     in_cell_size,
  90                     out_start_row,
  91                     padded_width;
  92        int out_start_col, /* can be negative to indicate padded space */
  93            table_cell_w;
  94        unsigned short *in_ptr,
  95                       *out_ptr;
  96
  97        assert(in_table != NULL);
  98        assert(out_table != NULL);
  99
 100        sensor_width  = in_table->sensor_width;
 101        sensor_height = in_table->sensor_height;
 102        table_width   = in_table->width;
 103        table_height  = in_table->height;
 104        in_ptr = in_table->data[color];
 105        out_ptr = out_table->data[color];
 106
 107        padded_width = cropped_width + left_padding + right_padding;
 108        out_cell_size = CEIL_DIV(padded_width, out_table->width - 1);
 109        in_cell_size  = CEIL_DIV(sensor_width, table_width - 1);
 110
 111        out_start_col = ((int)sensor_width - (int)cropped_width)/2 - left_padding;
 112        out_start_row = ((int)sensor_height - (int)cropped_height)/2 - top_padding;
 113        table_cell_w = (int)((table_width-1) * in_cell_size);
 114        table_cell_h = (table_height-1) * in_cell_size;
 115
 116        for (i = 0; i < out_table->height; i++) {
 117                int ty, src_y0, src_y1;
 118                unsigned int sy0, sy1, dy0, dy1, divy;
 119
 120                /* calculate target point and make sure it falls within
 121                   the table */
 122                ty = out_start_row + i * out_cell_size;
 123
 124                /* calculate closest source points in shading table and
 125                   make sure they fall within the table */
 126                src_y0 = ty / (int)in_cell_size;
 127                if (in_cell_size < out_cell_size)
 128                        src_y1 = (ty + out_cell_size) / in_cell_size;
 129                else
 130                        src_y1 = src_y0 + 1;
 131                src_y0 = clamp(src_y0, 0, (int)table_height-1);
 132                src_y1 = clamp(src_y1, 0, (int)table_height-1);
 133                ty = min(clamp(ty, 0, (int)sensor_height-1),
 134                                 (int)table_cell_h);
 135
 136                /* calculate closest source points for distance computation */
 137                sy0 = min(src_y0 * in_cell_size, sensor_height-1);
 138                sy1 = min(src_y1 * in_cell_size, sensor_height-1);
 139                /* calculate distance between source and target pixels */
 140                dy0 = ty - sy0;
 141                dy1 = sy1 - ty;
 142                divy = sy1 - sy0;
 143                if (divy == 0) {
 144                        dy0 = 1;
 145                        divy = 1;
 146                }
 147
 148                for (j = 0; j < out_table->width; j++, out_ptr++) {
 149                        int tx, src_x0, src_x1;
 150                        unsigned int sx0, sx1, dx0, dx1, divx;
 151                        unsigned short s_ul, s_ur, s_ll, s_lr;
 152
 153                        /* calculate target point */
 154                        tx = out_start_col + j * out_cell_size;
 155                        /* calculate closest source points. */
 156                        src_x0 = tx / (int)in_cell_size;
 157                        if (in_cell_size < out_cell_size) {
 158                                src_x1 = (tx + out_cell_size) /
 159                                         (int)in_cell_size;
 160                        } else {
 161                                src_x1 = src_x0 + 1;
 162                        }
 163                        /* if src points fall in padding, select closest ones.*/
 164                        src_x0 = clamp(src_x0, 0, (int)table_width-1);
 165                        src_x1 = clamp(src_x1, 0, (int)table_width-1);
 166                        tx = min(clamp(tx, 0, (int)sensor_width-1),
 167                                 (int)table_cell_w);
 168                        /* calculate closest source points for distance
 169                           computation */
 170                        sx0 = min(src_x0 * in_cell_size, sensor_width-1);
 171                        sx1 = min(src_x1 * in_cell_size, sensor_width-1);
 172                        /* calculate distances between source and target
 173                           pixels */
 174                        dx0 = tx - sx0;
 175                        dx1 = sx1 - tx;
 176                        divx = sx1 - sx0;
 177                        /* if we're at the edge, we just use the closest
 178                           point still in the grid. We make up for the divider
 179                           in this case by setting the distance to
 180                           out_cell_size, since it's actually 0. */
 181                        if (divx == 0) {
 182                                dx0 = 1;
 183                                divx = 1;
 184                        }
 185
 186                        /* get source pixel values */
 187                        s_ul = in_ptr[(table_width*src_y0)+src_x0];
 188                        s_ur = in_ptr[(table_width*src_y0)+src_x1];
 189                        s_ll = in_ptr[(table_width*src_y1)+src_x0];
 190                        s_lr = in_ptr[(table_width*src_y1)+src_x1];
 191
 192                        *out_ptr = (unsigned short) ((dx0*dy0*s_lr + dx0*dy1*s_ur + dx1*dy0*s_ll + dx1*dy1*s_ul) /
 193                                        (divx*divy));
 194                }
 195        }
 196}
 197
 198void
 199sh_css_params_shading_id_table_generate(
 200        struct ia_css_shading_table **target_table,
 201#ifndef ISP2401
 202        const struct ia_css_binary *binary)
 203#else
 204        unsigned int table_width,
 205        unsigned int table_height)
 206#endif
 207{
 208        /* initialize table with ones, shift becomes zero */
 209#ifndef ISP2401
 210        unsigned int i, j, table_width, table_height;
 211#else
 212        unsigned int i, j;
 213#endif
 214        struct ia_css_shading_table *result;
 215
 216        assert(target_table != NULL);
 217#ifndef ISP2401
 218        assert(binary != NULL);
 219#endif
 220
 221#ifndef ISP2401
 222        table_width  = binary->sctbl_width_per_color;
 223        table_height = binary->sctbl_height;
 224#endif
 225        result = ia_css_shading_table_alloc(table_width, table_height);
 226        if (result == NULL) {
 227                *target_table = NULL;
 228                return;
 229        }
 230
 231        for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) {
 232                for (j = 0; j < table_height * table_width; j++)
 233                        result->data[i][j] = 1;
 234        }
 235        result->fraction_bits = 0;
 236        *target_table = result;
 237}
 238
 239void
 240prepare_shading_table(const struct ia_css_shading_table *in_table,
 241                      unsigned int sensor_binning,
 242                      struct ia_css_shading_table **target_table,
 243                      const struct ia_css_binary *binary,
 244                      unsigned int bds_factor)
 245{
 246        unsigned int input_width,
 247                     input_height,
 248                     table_width,
 249                     table_height,
 250                     left_padding,
 251                     top_padding,
 252                     padded_width,
 253                     left_cropping,
 254                     i;
 255        unsigned int bds_numerator, bds_denominator;
 256        int right_padding;
 257
 258        struct ia_css_shading_table *result;
 259
 260        assert(target_table != NULL);
 261        assert(binary != NULL);
 262
 263        if (!in_table) {
 264#ifndef ISP2401
 265                sh_css_params_shading_id_table_generate(target_table, binary);
 266#else
 267                sh_css_params_shading_id_table_generate(target_table,
 268                        binary->sctbl_legacy_width_per_color, binary->sctbl_legacy_height);
 269#endif
 270                return;
 271        }
 272
 273        padded_width = binary->in_frame_info.padded_width;
 274        /* We use the ISP input resolution for the shading table because
 275           shading correction is performed in the bayer domain (before bayer
 276           down scaling). */
 277#if defined(USE_INPUT_SYSTEM_VERSION_2401)
 278        padded_width = CEIL_MUL(binary->effective_in_frame_res.width + 2*ISP_VEC_NELEMS,
 279                                        2*ISP_VEC_NELEMS);
 280#endif
 281        input_height  = binary->in_frame_info.res.height;
 282        input_width   = binary->in_frame_info.res.width;
 283        left_padding  = binary->left_padding;
 284        left_cropping = (binary->info->sp.pipeline.left_cropping == 0) ?
 285                        binary->dvs_envelope.width : 2*ISP_VEC_NELEMS;
 286
 287        sh_css_bds_factor_get_numerator_denominator
 288                (bds_factor, &bds_numerator, &bds_denominator);
 289
 290        left_padding  = (left_padding + binary->info->sp.pipeline.left_cropping) * bds_numerator / bds_denominator - binary->info->sp.pipeline.left_cropping;
 291        right_padding = (binary->internal_frame_info.res.width - binary->effective_in_frame_res.width * bds_denominator / bds_numerator - left_cropping) * bds_numerator / bds_denominator;
 292        top_padding = binary->info->sp.pipeline.top_cropping * bds_numerator / bds_denominator - binary->info->sp.pipeline.top_cropping;
 293
 294#if !defined(USE_WINDOWS_BINNING_FACTOR)
 295        /* @deprecated{This part of the code will be replaced by the code
 296         * in the #else section below to make the calculation same across
 297         * all platforms.
 298         * Android and Windows platforms interpret the binning_factor parameter
 299         * differently. In Android, the binning factor is expressed in the form
 300         * 2^N * 2^N, whereas in Windows platform, the binning factor is N*N}
 301         */
 302
 303        /* We take into account the binning done by the sensor. We do this
 304           by cropping the non-binned part of the shading table and then
 305           increasing the size of a grid cell with this same binning factor. */
 306        input_width  <<= sensor_binning;
 307        input_height <<= sensor_binning;
 308        /* We also scale the padding by the same binning factor. This will
 309           make it much easier later on to calculate the padding of the
 310           shading table. */
 311        left_padding  <<= sensor_binning;
 312        right_padding <<= sensor_binning;
 313        top_padding   <<= sensor_binning;
 314#else
 315        input_width   *= sensor_binning;
 316        input_height  *= sensor_binning;
 317        left_padding  *= sensor_binning;
 318        right_padding *= sensor_binning;
 319        top_padding   *= sensor_binning;
 320#endif /*USE_WINDOWS_BINNING_FACTOR*/
 321
 322        /* during simulation, the used resolution can exceed the sensor
 323           resolution, so we clip it. */
 324        input_width  = min(input_width,  in_table->sensor_width);
 325        input_height = min(input_height, in_table->sensor_height);
 326
 327#ifndef ISP2401
 328        table_width  = binary->sctbl_width_per_color;
 329        table_height = binary->sctbl_height;
 330#else
 331        /* This prepare_shading_table() function is called only in legacy API (not in new API).
 332           Then, the legacy shading table width and height should be used. */
 333        table_width  = binary->sctbl_legacy_width_per_color;
 334        table_height = binary->sctbl_legacy_height;
 335#endif
 336
 337        result = ia_css_shading_table_alloc(table_width, table_height);
 338        if (result == NULL) {
 339                *target_table = NULL;
 340                return;
 341        }
 342        result->sensor_width  = in_table->sensor_width;
 343        result->sensor_height = in_table->sensor_height;
 344        result->fraction_bits = in_table->fraction_bits;
 345
 346        /* now we crop the original shading table and then interpolate to the
 347           requested resolution and decimation factor. */
 348        for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) {
 349                crop_and_interpolate(input_width, input_height,
 350                                     left_padding, right_padding, top_padding,
 351                                     in_table,
 352                                     result, i);
 353        }
 354        *target_table = result;
 355}
 356
 357struct ia_css_shading_table *
 358ia_css_shading_table_alloc(
 359        unsigned int width,
 360        unsigned int height)
 361{
 362        unsigned int i;
 363        struct ia_css_shading_table *me;
 364
 365        IA_CSS_ENTER("");
 366
 367        me = kmalloc(sizeof(*me), GFP_KERNEL);
 368        if (me == NULL) {
 369                IA_CSS_ERROR("out of memory");
 370                return me;
 371        }
 372
 373        me->width         = width;
 374        me->height        = height;
 375        me->sensor_width  = 0;
 376        me->sensor_height = 0;
 377        me->fraction_bits = 0;
 378        for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) {
 379                me->data[i] =
 380                    sh_css_malloc(width * height * sizeof(*me->data[0]));
 381                if (me->data[i] == NULL) {
 382                        unsigned int j;
 383                        for (j = 0; j < i; j++) {
 384                                sh_css_free(me->data[j]);
 385                                me->data[j] = NULL;
 386                        }
 387                        kfree(me);
 388                        return NULL;
 389                }
 390        }
 391
 392        IA_CSS_LEAVE("");
 393        return me;
 394}
 395
 396void
 397ia_css_shading_table_free(struct ia_css_shading_table *table)
 398{
 399        unsigned int i;
 400
 401        if (table == NULL)
 402                return;
 403
 404        /* We only output logging when the table is not NULL, otherwise
 405         * logs will give the impression that a table was freed.
 406         * */
 407        IA_CSS_ENTER("");
 408
 409        for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) {
 410                if (table->data[i]) {
 411                        sh_css_free(table->data[i]);
 412                        table->data[i] = NULL;
 413                }
 414        }
 415        kfree(table);
 416
 417        IA_CSS_LEAVE("");
 418}
 419
 420