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 */ 73 static void 74 crop_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 200 void 201 sh_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 226 void 227 prepare_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, 234 input_height, 235 table_width, 236 table_height, 237 left_padding, 238 top_padding, 239 padded_width, 240 left_cropping, 241 i; 242 unsigned int bds_numerator, bds_denominator; 243 int right_padding; 244 245 struct ia_css_shading_table *result; 246 247 assert(target_table); 248 assert(binary); 249 250 if (!in_table) { 251 sh_css_params_shading_id_table_generate(target_table, 252 binary->sctbl_legacy_width_per_color, 253 binary->sctbl_legacy_height); 254 return; 255 } 256 257 padded_width = binary->in_frame_info.padded_width; 258 /* We use the ISP input resolution for the shading table because 259 shading correction is performed in the bayer domain (before bayer 260 down scaling). */ 261 #if defined(USE_INPUT_SYSTEM_VERSION_2401) 262 padded_width = CEIL_MUL(binary->effective_in_frame_res.width + 2 * 263 ISP_VEC_NELEMS, 264 2 * ISP_VEC_NELEMS); 265 #endif 266 input_height = binary->in_frame_info.res.height; 267 input_width = binary->in_frame_info.res.width; 268 left_padding = binary->left_padding; 269 left_cropping = (binary->info->sp.pipeline.left_cropping == 0) ? 270 binary->dvs_envelope.width : 2 * ISP_VEC_NELEMS; 271 272 sh_css_bds_factor_get_numerator_denominator 273 (bds_factor, &bds_numerator, &bds_denominator); 274 275 left_padding = (left_padding + binary->info->sp.pipeline.left_cropping) * 276 bds_numerator / bds_denominator - 277 binary->info->sp.pipeline.left_cropping; 278 right_padding = (binary->internal_frame_info.res.width - 279 binary->effective_in_frame_res.width * bds_denominator / 280 bds_numerator - left_cropping) * bds_numerator / bds_denominator; 281 top_padding = binary->info->sp.pipeline.top_cropping * bds_numerator / 282 bds_denominator - 283 binary->info->sp.pipeline.top_cropping; 284 285 #if !defined(USE_WINDOWS_BINNING_FACTOR) 286 /* @deprecated{This part of the code will be replaced by the code 287 * in the #else section below to make the calculation same across 288 * all platforms. 289 * Android and Windows platforms interpret the binning_factor parameter 290 * differently. In Android, the binning factor is expressed in the form 291 * 2^N * 2^N, whereas in Windows platform, the binning factor is N*N} 292 */ 293 294 /* We take into account the binning done by the sensor. We do this 295 by cropping the non-binned part of the shading table and then 296 increasing the size of a grid cell with this same binning factor. */ 297 input_width <<= sensor_binning; 298 input_height <<= sensor_binning; 299 /* We also scale the padding by the same binning factor. This will 300 make it much easier later on to calculate the padding of the 301 shading table. */ 302 left_padding <<= sensor_binning; 303 right_padding <<= sensor_binning; 304 top_padding <<= sensor_binning; 305 #else 306 input_width *= sensor_binning; 307 input_height *= sensor_binning; 308 left_padding *= sensor_binning; 309 right_padding *= sensor_binning; 310 top_padding *= sensor_binning; 311 #endif /*USE_WINDOWS_BINNING_FACTOR*/ 312 313 /* during simulation, the used resolution can exceed the sensor 314 resolution, so we clip it. */ 315 input_width = min(input_width, in_table->sensor_width); 316 input_height = min(input_height, in_table->sensor_height); 317 318 /* This prepare_shading_table() function is called only in legacy API (not in new API). 319 Then, the legacy shading table width and height should be used. */ 320 table_width = binary->sctbl_legacy_width_per_color; 321 table_height = binary->sctbl_legacy_height; 322 323 result = ia_css_shading_table_alloc(table_width, table_height); 324 if (!result) { 325 *target_table = NULL; 326 return; 327 } 328 result->sensor_width = in_table->sensor_width; 329 result->sensor_height = in_table->sensor_height; 330 result->fraction_bits = in_table->fraction_bits; 331 332 /* now we crop the original shading table and then interpolate to the 333 requested resolution and decimation factor. */ 334 for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) { 335 crop_and_interpolate(input_width, input_height, 336 left_padding, right_padding, top_padding, 337 in_table, 338 result, i); 339 } 340 *target_table = result; 341 } 342 343 struct ia_css_shading_table * 344 ia_css_shading_table_alloc( 345 unsigned int width, 346 unsigned int height) 347 { 348 unsigned int i; 349 struct ia_css_shading_table *me; 350 351 IA_CSS_ENTER(""); 352 353 me = kmalloc(sizeof(*me), GFP_KERNEL); 354 if (!me) 355 return me; 356 357 me->width = width; 358 me->height = height; 359 me->sensor_width = 0; 360 me->sensor_height = 0; 361 me->fraction_bits = 0; 362 for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) { 363 me->data[i] = 364 kvmalloc(width * height * sizeof(*me->data[0]), 365 GFP_KERNEL); 366 if (!me->data[i]) { 367 unsigned int j; 368 369 for (j = 0; j < i; j++) { 370 kvfree(me->data[j]); 371 me->data[j] = NULL; 372 } 373 kfree(me); 374 return NULL; 375 } 376 } 377 378 IA_CSS_LEAVE(""); 379 return me; 380 } 381 382 void 383 ia_css_shading_table_free(struct ia_css_shading_table *table) 384 { 385 unsigned int i; 386 387 if (!table) 388 return; 389 390 /* We only output logging when the table is not NULL, otherwise 391 * logs will give the impression that a table was freed. 392 * */ 393 IA_CSS_ENTER(""); 394 395 for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) { 396 if (table->data[i]) { 397 kvfree(table->data[i]); 398 table->data[i] = NULL; 399 } 400 } 401 kfree(table); 402 403 IA_CSS_LEAVE(""); 404 } 405