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