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