1 /*
2 *
3 * SPDX-License-Identifier: GPL-2.0
4 *
5 * Copyright (C) 2011-2018 ARM or its affiliates
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20 #include "acamera_fw.h"
21
22 #include "acamera_math.h"
23 #include "acamera_math.h"
24 #include "acamera_calibrations.h"
25 #include "acamera_command_api.h"
26 #include "matrix_yuv_fsm.h"
27
28 #ifdef LOG_MODULE
29 #undef LOG_MODULE
30 #define LOG_MODULE LOG_MODULE_MATRIX_YUV
31 #endif
32
vector_vector_add(int16_t * v1,int16_t * v2,int dim1)33 static void vector_vector_add( int16_t *v1, int16_t *v2, int dim1 )
34 {
35 int i;
36 for ( i = 0; i < dim1; ++i ) {
37 v2[i] = v1[i] + v2[i];
38 }
39 }
matrix_vector_multiply(int16_t * m,int16_t * v)40 static void matrix_vector_multiply( int16_t *m, int16_t *v )
41 {
42 int i, j;
43 const int dim1 = 3;
44 const int dim2 = 3;
45 int16_t result[3];
46 for ( i = 0; i < dim1; ++i ) {
47 int32_t temp = 0;
48 for ( j = 0; j < dim2; ++j )
49 temp += ( ( (int32_t)m[i * dim2 + j] * v[j] ) );
50 result[i] = (uint16_t)( ( temp + ( 1 << 7 ) ) >> 8 );
51 }
52 for ( i = 0; i < dim1; ++i )
53 v[i] = ACAMERA_MAX( -1023, ACAMERA_MIN( 1023, result[i] ) );
54 }
matrix_matrix_multiply(int16_t * a1,int16_t * a2)55 static void matrix_matrix_multiply( int16_t *a1, int16_t *a2 )
56 {
57 int i, j, k;
58 const int dim1 = 3;
59 const int dim2 = 3;
60 const int dim3 = 3;
61 int16_t result[3 * 3];
62
63 memset( result, 0, sizeof( result ) );
64
65 for ( i = 0; i < dim1; ++i ) {
66 for ( j = 0; j < dim3; ++j ) {
67 int32_t temp = 0;
68 for ( k = 0; k < dim2; ++k )
69 temp += ( ( (int32_t)a1[i * dim2 + k] * a2[k * dim3 + j] ) );
70 result[i * dim3 + j] = (int16_t)( ( temp + ( 1 << 7 ) ) >> 8 );
71 }
72 }
73 for ( i = 0; i < 9; i++ )
74 a2[i] = result[i]; //ACAMERA_MAX(-511,ACAMERA_MIN(512,result[i]));
75 }
76
color_matrix_complement_to_direct_16(int16_t v)77 static uint16_t color_matrix_complement_to_direct_16( int16_t v )
78 {
79 uint16_t result;
80
81 if ( v >= 0 )
82 result = v;
83 else {
84 result = -v;
85 result |= ( 1 << 15 );
86 }
87 return result;
88 }
89
matrix_yuv_clip(int16_t * input)90 static void matrix_yuv_clip( int16_t *input )
91 {
92 uint8_t i;
93 int16_t val;
94 for ( i = 0; i < 9; i++ ) {
95 val = ACAMERA_MAX( -511, ACAMERA_MIN( 512, input[i] ) );
96 input[i] = color_matrix_complement_to_direct_16( val );
97 }
98 for ( i = 9; i < 12; i++ ) {
99 val = ACAMERA_MAX( -1023, ACAMERA_MIN( 1023, input[i] ) );
100 input[i] = val;
101 if ( val < 0 ) {
102 val = 2048 + val;
103 input[i] = val;
104 }
105 }
106 }
matrix_yuv_fr_coefft_write_to_hardware(matrix_yuv_fsm_t * p_fsm)107 static void matrix_yuv_fr_coefft_write_to_hardware( matrix_yuv_fsm_t *p_fsm )
108 {
109 // set U and V channel to 0 in black and white mode
110 int i = 0;
111 if ( p_fsm->color_mode == BLACK_AND_WHITE ) {
112 for ( i = 3; i < 9; i++ ) {
113 p_fsm->fr_composite_yuv_matrix[i] = 0;
114 }
115 p_fsm->fr_composite_yuv_matrix[9] = 0;
116 p_fsm->fr_composite_yuv_matrix[10] = 512;
117 p_fsm->fr_composite_yuv_matrix[11] = 512;
118 }
119
120 int16_t *yuv_matrix = p_fsm->fr_composite_yuv_matrix;
121 acamera_isp_fr_cs_conv_coefft_11_write( p_fsm->cmn.isp_base, yuv_matrix[0] );
122 acamera_isp_fr_cs_conv_coefft_12_write( p_fsm->cmn.isp_base, yuv_matrix[1] );
123 acamera_isp_fr_cs_conv_coefft_13_write( p_fsm->cmn.isp_base, yuv_matrix[2] );
124 acamera_isp_fr_cs_conv_coefft_21_write( p_fsm->cmn.isp_base, yuv_matrix[3] );
125 acamera_isp_fr_cs_conv_coefft_22_write( p_fsm->cmn.isp_base, yuv_matrix[4] );
126 acamera_isp_fr_cs_conv_coefft_23_write( p_fsm->cmn.isp_base, yuv_matrix[5] );
127 acamera_isp_fr_cs_conv_coefft_31_write( p_fsm->cmn.isp_base, yuv_matrix[6] );
128 acamera_isp_fr_cs_conv_coefft_32_write( p_fsm->cmn.isp_base, yuv_matrix[7] );
129 acamera_isp_fr_cs_conv_coefft_33_write( p_fsm->cmn.isp_base, yuv_matrix[8] );
130 acamera_isp_fr_cs_conv_coefft_o1_write( p_fsm->cmn.isp_base, yuv_matrix[9] );
131 acamera_isp_fr_cs_conv_coefft_o2_write( p_fsm->cmn.isp_base, yuv_matrix[10] );
132 acamera_isp_fr_cs_conv_coefft_o3_write( p_fsm->cmn.isp_base, yuv_matrix[11] );
133 acamera_isp_fr_cs_conv_enable_matrix_write( p_fsm->cmn.isp_base, 1 );
134 switch ( p_fsm->fr_pipe_output_format ) {
135 case PIPE_OUT_YUV422:
136 acamera_isp_fr_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 1 );
137 acamera_isp_fr_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 1 );
138 acamera_isp_fr_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 0 );
139
140 break;
141 case PIPE_OUT_YUV420:
142 acamera_isp_fr_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 1 );
143 acamera_isp_fr_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 1 );
144 acamera_isp_fr_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 1 );
145
146 break;
147 case PIPE_OUT_RGB:
148 acamera_isp_fr_cs_conv_coefft_11_write( p_fsm->cmn.isp_base, yuv_matrix[6] );
149 acamera_isp_fr_cs_conv_coefft_12_write( p_fsm->cmn.isp_base, yuv_matrix[7] );
150 acamera_isp_fr_cs_conv_coefft_13_write( p_fsm->cmn.isp_base, yuv_matrix[8] );
151 acamera_isp_fr_cs_conv_coefft_21_write( p_fsm->cmn.isp_base, yuv_matrix[3] );
152 acamera_isp_fr_cs_conv_coefft_22_write( p_fsm->cmn.isp_base, yuv_matrix[4] );
153 acamera_isp_fr_cs_conv_coefft_23_write( p_fsm->cmn.isp_base, yuv_matrix[5] );
154 acamera_isp_fr_cs_conv_coefft_31_write( p_fsm->cmn.isp_base, yuv_matrix[0] );
155 acamera_isp_fr_cs_conv_coefft_32_write( p_fsm->cmn.isp_base, yuv_matrix[1] );
156 acamera_isp_fr_cs_conv_coefft_33_write( p_fsm->cmn.isp_base, yuv_matrix[2] );
157 acamera_isp_fr_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 0 );
158 acamera_isp_fr_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 0 );
159 acamera_isp_fr_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 0 );
160
161 break;
162 case PIPE_OUT_YUV444:
163 acamera_isp_fr_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 0 );
164 acamera_isp_fr_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 0 );
165 acamera_isp_fr_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 0 );
166
167 break;
168 default:
169 acamera_isp_fr_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 0 );
170 acamera_isp_fr_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 0 );
171 acamera_isp_fr_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 0 );
172 break;
173 }
174 }
175
matrix_yuv_ds_write_to_hardware(matrix_yuv_fsm_t * p_fsm)176 static void matrix_yuv_ds_write_to_hardware( matrix_yuv_fsm_t *p_fsm )
177 {
178 // set U and V channel to 0 in black and white mode
179 int i = 0;
180 if ( p_fsm->color_mode == BLACK_AND_WHITE ) {
181 for ( i = 3; i < 9; i++ ) {
182 p_fsm->fr_composite_yuv_matrix[i] = 0;
183 }
184 p_fsm->fr_composite_yuv_matrix[9] = 0;
185 p_fsm->fr_composite_yuv_matrix[10] = 512;
186 p_fsm->fr_composite_yuv_matrix[11] = 512;
187 }
188
189 #if ISP_HAS_DS1
190 int16_t *yuv_matrix = p_fsm->ds1_composite_yuv_matrix;
191 acamera_isp_ds1_cs_conv_coefft_11_write( p_fsm->cmn.isp_base, yuv_matrix[0] );
192 acamera_isp_ds1_cs_conv_coefft_12_write( p_fsm->cmn.isp_base, yuv_matrix[1] );
193 acamera_isp_ds1_cs_conv_coefft_13_write( p_fsm->cmn.isp_base, yuv_matrix[2] );
194 acamera_isp_ds1_cs_conv_coefft_21_write( p_fsm->cmn.isp_base, yuv_matrix[3] );
195 acamera_isp_ds1_cs_conv_coefft_22_write( p_fsm->cmn.isp_base, yuv_matrix[4] );
196 acamera_isp_ds1_cs_conv_coefft_23_write( p_fsm->cmn.isp_base, yuv_matrix[5] );
197 acamera_isp_ds1_cs_conv_coefft_31_write( p_fsm->cmn.isp_base, yuv_matrix[6] );
198 acamera_isp_ds1_cs_conv_coefft_32_write( p_fsm->cmn.isp_base, yuv_matrix[7] );
199 acamera_isp_ds1_cs_conv_coefft_33_write( p_fsm->cmn.isp_base, yuv_matrix[8] );
200 acamera_isp_ds1_cs_conv_coefft_o1_write( p_fsm->cmn.isp_base, yuv_matrix[9] );
201 acamera_isp_ds1_cs_conv_coefft_o2_write( p_fsm->cmn.isp_base, yuv_matrix[10] );
202 acamera_isp_ds1_cs_conv_coefft_o3_write( p_fsm->cmn.isp_base, yuv_matrix[11] );
203 acamera_isp_ds1_cs_conv_enable_matrix_write( p_fsm->cmn.isp_base, 1 );
204 switch ( p_fsm->ds1_pipe_output_format ) {
205 case PIPE_OUT_YUV422:
206 acamera_isp_ds1_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 1 );
207 acamera_isp_ds1_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 1 );
208 acamera_isp_ds1_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 0 );
209 break;
210 case PIPE_OUT_YUV420:
211 acamera_isp_ds1_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 1 );
212 acamera_isp_ds1_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 1 );
213 acamera_isp_ds1_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 1 );
214 break;
215 case PIPE_OUT_RGB:
216 acamera_isp_ds1_cs_conv_coefft_11_write( p_fsm->cmn.isp_base, yuv_matrix[6] );
217 acamera_isp_ds1_cs_conv_coefft_12_write( p_fsm->cmn.isp_base, yuv_matrix[7] );
218 acamera_isp_ds1_cs_conv_coefft_13_write( p_fsm->cmn.isp_base, yuv_matrix[8] );
219 acamera_isp_ds1_cs_conv_coefft_21_write( p_fsm->cmn.isp_base, yuv_matrix[3] );
220 acamera_isp_ds1_cs_conv_coefft_22_write( p_fsm->cmn.isp_base, yuv_matrix[4] );
221 acamera_isp_ds1_cs_conv_coefft_23_write( p_fsm->cmn.isp_base, yuv_matrix[5] );
222 acamera_isp_ds1_cs_conv_coefft_31_write( p_fsm->cmn.isp_base, yuv_matrix[0] );
223 acamera_isp_ds1_cs_conv_coefft_32_write( p_fsm->cmn.isp_base, yuv_matrix[1] );
224 acamera_isp_ds1_cs_conv_coefft_33_write( p_fsm->cmn.isp_base, yuv_matrix[2] );
225 acamera_isp_ds1_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 0 );
226 acamera_isp_ds1_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 0 );
227 acamera_isp_ds1_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 0 );
228 break;
229 case PIPE_OUT_YUV444:
230 acamera_isp_ds1_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 0 );
231 acamera_isp_ds1_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 0 );
232 acamera_isp_ds1_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 0 );
233 break;
234 default:
235 acamera_isp_ds1_cs_conv_enable_filter_write( p_fsm->cmn.isp_base, 0 );
236 acamera_isp_ds1_cs_conv_enable_horizontal_downsample_write( p_fsm->cmn.isp_base, 0 );
237 acamera_isp_ds1_cs_conv_enable_vertical_downsample_write( p_fsm->cmn.isp_base, 0 );
238 break;
239 }
240 #endif
241 }
242
matrix_compute_brightness(uint8_t brightness_strength,int16_t * p_matrix)243 static void matrix_compute_brightness( uint8_t brightness_strength, int16_t *p_matrix )
244 {
245
246 /*{
247 Chainging Brigntess in the RGB domain.So apply the same shift to all the Colors.
248 In Case if the PIPE output is YUV,the YUC transform matrix will apply the offset only on to the Y channel
249 and for the U and V the co-eff of you YUV transform matrix is such that it will add up to zero.
250 The idea here is to change Brigtness in RGB
251 by changing offset for RGB
252 0x100 0 0 brightness_shift
253 0 0x100 0 brightness_shift
254 0 0 0x100 brightness_shift
255 }
256 */
257 int16_t brightness_shift = 0;
258 uint8_t i = 0;
259 if ( brightness_strength < 128 ) {
260 brightness_shift = -( ( 0x3FF * ( 127 - brightness_strength ) ) / 127 );
261 } else {
262 brightness_shift = ( 0x3FF * ( brightness_strength - 128 ) ) / 127;
263 }
264 for ( i = 0; i < 12; i++ )
265 p_matrix[i] = 0x00;
266 for ( i = 0; i < 9; i += 4 ) {
267 p_matrix[i] = 0x100;
268 }
269 p_matrix[9] = brightness_shift;
270 p_matrix[10] = brightness_shift;
271 p_matrix[11] = brightness_shift;
272 }
matrix_compute_saturation(uint8_t saturation_strength,int16_t * p_matrix,matrix_yuv_fsm_t * p_fsm)273 static void matrix_compute_saturation( uint8_t saturation_strength, int16_t *p_matrix, matrix_yuv_fsm_t *p_fsm )
274 {
275 /*{
276 The idea here is to change Saturation only by changing the U anv V channels.
277 But we are applying on RGB
278 X25 = RGB2YUV\([1 0 0; 0 2 0; 0 0 2]*RGB2YUV)
279 X = (X25-eye(3))
280 That is the saturation_transfrom_mat.
281 }*/
282 int16_t saturation_transfrom_mat[12] = {179, -149, -28, -76, 104, -29, -75, -148, 226, 0, 0, 0};
283 int16_t saturation_scale = 0;
284 if ( saturation_strength < 128 )
285 saturation_scale = 256 * ( saturation_strength - 128 ) / 128;
286 else
287 saturation_scale = ( 256 * ( (uint16_t)saturation_strength - 128 ) ) / 128;
288 uint8_t i = 0;
289 for ( i = 0; i < 12; i++ )
290 p_matrix[i] = ( saturation_transfrom_mat[i] * saturation_scale ) >> 8;
291 p_matrix[0] += 0x100;
292 p_matrix[4] += 0x100;
293 p_matrix[8] += 0x100;
294 }
matrix_compute_contrast(uint8_t contrast_strength,int16_t * p_matrix)295 static void matrix_compute_contrast( uint8_t contrast_strength, int16_t *p_matrix )
296 {
297 /*{
298 The idea here is to change Contrast,by scaling RGB space and changing offset
299 contrast_scale 0 0 contrast_shift
300 0 contrast_scale 0 0
301 0 0 contrast_scale 0
302 }
303 */
304 int16_t contrast_scale = 0;
305 int16_t contrast_shift = 0;
306 uint8_t i = 0;
307 if ( contrast_strength <= 128 ) {
308 contrast_scale = ( 256 * contrast_strength ) / 128;
309 contrast_shift = 512 - ( ( 512 * contrast_strength ) / 128 );
310 } else {
311 contrast_scale = 256 + ( ( 256 * ( contrast_strength - 128 ) ) / 128 );
312 contrast_shift = ( 512 * ( 128 - contrast_strength ) ) / 128;
313 }
314 for ( i = 0; i < 12; i++ )
315 p_matrix[i] = 0;
316
317 p_matrix[0] = contrast_scale;
318 p_matrix[4] = contrast_scale;
319 p_matrix[8] = contrast_scale;
320 p_matrix[9] = contrast_shift;
321 p_matrix[10] = contrast_shift;
322 p_matrix[11] = contrast_shift;
323 }
324
325 #define MUL_16_16( a, b ) ( ( int16_t )( ( (int32_t)a * (int32_t)b ) >> 15 ) )
get_cosine(int16_t theta,int16_t * p_hue_COS_TABLES)326 static int16_t get_cosine( int16_t theta, int16_t *p_hue_COS_TABLES )
327 {
328 int16_t result = 0;
329 int8_t index = 0;
330 int8_t sign = 0;
331 if ( theta >= 0 && theta <= 90 ) {
332 index = theta;
333 sign = 1;
334 } else if ( theta > 90 && theta <= 180 ) {
335 sign = -1;
336 index = 180 - theta;
337 } else if ( theta < 0 && theta >= -90 ) {
338 sign = 1;
339 index = -theta;
340 } else if ( theta < -90 && theta >= -180 ) {
341 sign = -1;
342 index = 180 + theta;
343 }
344 result = sign * ( p_hue_COS_TABLES[index] + ( 90 - index ) );
345 return result;
346 }
get_sine(int16_t theta,int16_t * p_hue_COS_TABLES)347 static int16_t get_sine( int16_t theta, int16_t *p_hue_COS_TABLES )
348 {
349 int16_t result = 0;
350 int8_t index = 0;
351 int8_t sign = 0;
352 if ( theta >= 0 && theta <= 90 ) {
353 index = 90 - theta;
354 sign = 1;
355 } else if ( theta > 90 && theta <= 180 ) {
356 sign = 1;
357 index = theta - 90;
358 } else if ( theta < -90 && theta >= -180 ) {
359 sign = -1;
360 index = -( theta + 90 );
361 } else if ( theta < 0 && theta >= -90 ) {
362 sign = -1;
363 index = 90 + theta;
364 }
365 result = sign * ( p_hue_COS_TABLES[index] + ( 90 - index ) );
366 return result;
367 }
matrix_compute_hue_saturation(uint16_t value,int16_t * p_matrix)368 static void matrix_compute_hue_saturation( uint16_t value, int16_t *p_matrix )
369 {
370 /*
371 The Hue Correction is applied in YIQ domain.RGB->YIQ->HUE_COORECTION->RGB
372 The entire transform matrix YIQ2RGB*Hue_Corr*RGB2YIQ(Image),is simplified into one matrix, and given by the hue coeff which is 3x3 matrix and each column has 3 coeff
373 in the form a0+b0*cosine+c0*sine.
374 All the tables used here are Q14 format.Results in Q8 format.
375
376 */
377 int16_t HUE_COSTABLE[] = {
378 16294, 16293, 16286, 16275, 16258, 16237, 16210, 16179, 16143, 16101, 16055, 16004, 15948, 15887, 15821, 15751,
379 15675, 15595, 15510, 15420, 15326, 15227, 15123, 15015, 14902, 14784, 14662, 14535, 14404, 14269, 14129, 13985,
380 13836, 13684, 13527, 13366, 13201, 13032, 12859, 12682, 12501, 12316, 12128, 11935, 11740, 11540, 11337, 11131,
381 10921, 10708, 10491, 10272, 10049, 9823, 9594, 9362, 9128, 8890, 8650, 8407, 8162, 7914, 7664, 7411, 7156, 6899,
382 6640, 6379, 6116, 5851, 5584, 5315, 5045, 4773, 4500, 4225, 3950, 3673, 3394, 3115, 2835, 2554, 2272, 1990, 1707,
383 1423, 1139, 854, 570, 285, 0,
384 };
385 int16_t hue_coeff[] = {
386 4899, 11485, 2748, 9617, -9617, 5395, 1868, -1868, -8144, 4899, -4899, -5376, 9617, 6767, 581, 1868, -1868, 4795,
387 4899, -4899, 20473, 9617, -9617, -17143, 1868, 14516, -3329,
388 };
389 int16_t theta = (int16_t)value;
390 int16_t cosine = 0;
391 int16_t sine = 0;
392 uint8_t _index = 0;
393 const int16_t identity_matrix[12] = {0x0100, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 0x0100, 0, 0, 0};
394 for ( _index = 0; _index < 12; _index++ )
395 p_matrix[_index] = identity_matrix[_index];
396
397 theta = theta - 180;
398 cosine = get_cosine( theta, HUE_COSTABLE );
399 sine = get_sine( theta, HUE_COSTABLE );
400 for ( _index = 0; _index < 9; _index++ ) {
401 p_matrix[_index] = ( hue_coeff[0 + ( _index * 3 )] >> 1 ) + MUL_16_16( hue_coeff[1 + ( _index * 3 )], cosine ) + MUL_16_16( hue_coeff[2 + ( _index * 3 )], sine );
402 p_matrix[_index] = p_matrix[_index] >> 5; //(Q13->Q8)
403 if (theta == 0)
404 p_matrix[_index] = identity_matrix[_index];
405 }
406 }
matrix_compute_color_mode(uint16_t mode,int16_t * p_color_mode_matrix,matrix_yuv_fsm_t * p_fsm)407 static void matrix_compute_color_mode( uint16_t mode, int16_t *p_color_mode_matrix, matrix_yuv_fsm_t *p_fsm )
408 {
409 const int16_t identity_matrix[12] = {0x0100, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 0x0100, 0, 0, 0};
410 uint8_t i;
411 for ( i = 0; i < 12; i++ )
412 p_color_mode_matrix[i] = identity_matrix[i];
413 #ifdef COLOR_MODE_ID
414 uint8_t j;
415
416 switch ( mode ) {
417 case NORMAL:
418 for ( i = 0; i < 3; i++ ) {
419 for ( j = 0; j < 3; j++ ) {
420 if ( i == j )
421 p_color_mode_matrix[3 * i + j] = 0x100;
422 else
423 p_color_mode_matrix[3 * i + j] = 0;
424 }
425 }
426 for ( i = 9; i < 12; i++ )
427 p_color_mode_matrix[i] = 0;
428 break;
429 case BLACK_AND_WHITE:
430 for ( i = 0; i < 3; i++ ) {
431 for ( j = 0; j < 3; j++ ) {
432 p_color_mode_matrix[3 * i + j] = p_fsm->rgb2yuv_matrix[j];
433 }
434 }
435 for ( i = 9; i < 12; i++ )
436 p_color_mode_matrix[i] = 0;
437 break;
438 case NEGATIVE:
439 for ( i = 0; i < 3; i++ ) {
440 for ( j = 0; j < 3; j++ ) {
441 if ( i == j )
442 p_color_mode_matrix[3 * i + j] = -0x100;
443 else
444 p_color_mode_matrix[3 * i + j] = 0;
445 }
446 }
447 for ( i = 9; i < 12; i++ )
448 p_color_mode_matrix[i] = 0x3ff;
449 break;
450 case SEPIA: // get values from IQ:
451 p_color_mode_matrix[0] = 0x75;
452 p_color_mode_matrix[1] = 0x15;
453 p_color_mode_matrix[2] = 0x05;
454 p_color_mode_matrix[3] = 0x20;
455 p_color_mode_matrix[4] = 0x70;
456 p_color_mode_matrix[5] = 0x05;
457 p_color_mode_matrix[6] = 0x20;
458 p_color_mode_matrix[7] = 0x20;
459 p_color_mode_matrix[8] = 0x05;
460 p_color_mode_matrix[9] = 0xD3;
461 p_color_mode_matrix[10] = 0x0;
462 p_color_mode_matrix[11] = 0x0;
463 break;
464 case VIVID:
465 for ( i = 0; i < 3; i++ ) {
466 for ( j = 0; j < 3; j++ ) {
467 if ( i == j )
468 p_color_mode_matrix[3 * i + j] = 0x100;
469 else
470 p_color_mode_matrix[3 * i + j] = 0;
471 }
472 }
473 for ( i = 9; i < 12; i++ )
474 p_color_mode_matrix[i] = 0;
475 break;
476 default:
477 break;
478 }
479 #endif
480 }
update_composite_matrix(int16_t * inp1,int16_t * res)481 static void update_composite_matrix( int16_t *inp1, int16_t *res )
482 {
483 matrix_matrix_multiply( inp1, res );
484 matrix_vector_multiply( inp1, res + 9 );
485
486 vector_vector_add( inp1 + 9, res + 9, 3 );
487 }
compute_transfrom_matrix(matrix_yuv_fsm_t * p_fsm,int16_t * final_composite_yuv_matrix,uint8_t format)488 static void compute_transfrom_matrix( matrix_yuv_fsm_t *p_fsm, int16_t *final_composite_yuv_matrix, uint8_t format )
489 {
490 uint8_t i = 0;
491 uint16_t identity_matrix[12] = {0x0100, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 0x0100, 0, 0, 0};
492 for ( i = 0; i < 12; i++ ) {
493 final_composite_yuv_matrix[i] = identity_matrix[i];
494 }
495 update_composite_matrix( p_fsm->color_mode_matrix, final_composite_yuv_matrix );
496 update_composite_matrix( p_fsm->hue_correction_matrix, final_composite_yuv_matrix );
497 update_composite_matrix( p_fsm->saturation_matrix, final_composite_yuv_matrix );
498 update_composite_matrix( p_fsm->contrast_matrix, final_composite_yuv_matrix );
499 update_composite_matrix( p_fsm->brightness_matrix, final_composite_yuv_matrix );
500 if ( format != PIPE_OUT_RGB ) {
501 uint16_t *ptr_rgb2yuv = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_RGB2YUV_CONVERSION );
502 for ( i = 0; i < 12; i++ )
503 p_fsm->rgb2yuv_matrix[i] = color_matrix_direct_to_complement( ptr_rgb2yuv[i] );
504 update_composite_matrix( p_fsm->rgb2yuv_matrix, final_composite_yuv_matrix );
505 }
506 matrix_yuv_clip( final_composite_yuv_matrix );
507 }
matrix_yuv_recompute(matrix_yuv_fsm_t * p_fsm)508 void matrix_yuv_recompute( matrix_yuv_fsm_t *p_fsm )
509 {
510
511 matrix_compute_color_mode( p_fsm->color_mode, p_fsm->color_mode_matrix, p_fsm );
512 matrix_compute_brightness( p_fsm->brightness_strength, p_fsm->brightness_matrix );
513 matrix_compute_contrast( p_fsm->contrast_strength, p_fsm->contrast_matrix );
514 matrix_compute_saturation( p_fsm->saturation_strength, p_fsm->saturation_matrix, p_fsm );
515 matrix_compute_hue_saturation( p_fsm->hue_theta, p_fsm->hue_correction_matrix );
516 compute_transfrom_matrix( p_fsm, p_fsm->fr_composite_yuv_matrix, p_fsm->fr_pipe_output_format );
517 #if ISP_HAS_DS1
518 compute_transfrom_matrix( p_fsm, p_fsm->ds1_composite_yuv_matrix, p_fsm->ds1_pipe_output_format );
519 #endif
520 }
matrix_yuv_coefft_write_to_hardware(matrix_yuv_fsm_t * p_fsm)521 void matrix_yuv_coefft_write_to_hardware( matrix_yuv_fsm_t *p_fsm )
522 {
523 matrix_yuv_fr_coefft_write_to_hardware( p_fsm );
524 matrix_yuv_ds_write_to_hardware( p_fsm );
525 }
matrix_yuv_update(matrix_yuv_fsm_t * p_fsm)526 void matrix_yuv_update( matrix_yuv_fsm_t *p_fsm )
527 {
528 matrix_yuv_recompute( p_fsm );
529 matrix_yuv_coefft_write_to_hardware( p_fsm );
530 }
matrix_yuv_initialize(matrix_yuv_fsm_t * p_fsm)531 void matrix_yuv_initialize( matrix_yuv_fsm_t *p_fsm )
532 {
533 uint16_t identity_matrix[12] = {0x0100, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 0x0100, 0, 0, 0};
534 uint8_t i = 0;
535 p_fsm->saturation_strength = 128;
536 p_fsm->contrast_strength = 128;
537 p_fsm->brightness_strength = 128;
538 p_fsm->hue_theta = 180;
539 #if defined( COLOR_MODE_ID )
540 p_fsm->color_mode = NORMAL;
541 #endif
542 for ( i = 0; i < 12; i++ ) {
543 p_fsm->rgb2yuv_matrix[i] = color_matrix_direct_to_complement( identity_matrix[i] );
544 p_fsm->brightness_matrix[i] = color_matrix_direct_to_complement( identity_matrix[i] );
545 p_fsm->contrast_matrix[i] = color_matrix_direct_to_complement( identity_matrix[i] );
546 p_fsm->hue_correction_matrix[i] = color_matrix_direct_to_complement( identity_matrix[i] );
547 p_fsm->fr_composite_yuv_matrix[i] = color_matrix_direct_to_complement( identity_matrix[i] );
548 #if ISP_HAS_DS1
549 p_fsm->ds1_composite_yuv_matrix[i] = color_matrix_direct_to_complement( identity_matrix[i] );
550 #endif
551 }
552 }
553
554
matrix_yuv_set_DS1_mode(const uint16_t format)555 void matrix_yuv_set_DS1_mode( const uint16_t format )
556 {
557 }
matrix_yuv_set_FR_mode(const uint16_t format)558 void matrix_yuv_set_FR_mode( const uint16_t format )
559 {
560 }
561