1 /*
2 * Copyright 2016 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26 #include "dc.h"
27 #include "opp.h"
28 #include "color_gamma.h"
29
30
31 #define NUM_PTS_IN_REGION 16
32 #define NUM_REGIONS 32
33 #define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS)
34
35 static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2];
36
37 static struct fixed31_32 pq_table[MAX_HW_POINTS + 2];
38 static struct fixed31_32 de_pq_table[MAX_HW_POINTS + 2];
39
40 static bool pq_initialized; /* = false; */
41 static bool de_pq_initialized; /* = false; */
42
43 /* one-time setup of X points */
setup_x_points_distribution(void)44 void setup_x_points_distribution(void)
45 {
46 struct fixed31_32 region_size = dc_fixpt_from_int(128);
47 int32_t segment;
48 uint32_t seg_offset;
49 uint32_t index;
50 struct fixed31_32 increment;
51
52 coordinates_x[MAX_HW_POINTS].x = region_size;
53 coordinates_x[MAX_HW_POINTS + 1].x = region_size;
54
55 for (segment = 6; segment > (6 - NUM_REGIONS); segment--) {
56 region_size = dc_fixpt_div_int(region_size, 2);
57 increment = dc_fixpt_div_int(region_size,
58 NUM_PTS_IN_REGION);
59 seg_offset = (segment + (NUM_REGIONS - 7)) * NUM_PTS_IN_REGION;
60 coordinates_x[seg_offset].x = region_size;
61
62 for (index = seg_offset + 1;
63 index < seg_offset + NUM_PTS_IN_REGION;
64 index++) {
65 coordinates_x[index].x = dc_fixpt_add
66 (coordinates_x[index-1].x, increment);
67 }
68 }
69 }
70
compute_pq(struct fixed31_32 in_x,struct fixed31_32 * out_y)71 static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
72 {
73 /* consts for PQ gamma formula. */
74 const struct fixed31_32 m1 =
75 dc_fixpt_from_fraction(159301758, 1000000000);
76 const struct fixed31_32 m2 =
77 dc_fixpt_from_fraction(7884375, 100000);
78 const struct fixed31_32 c1 =
79 dc_fixpt_from_fraction(8359375, 10000000);
80 const struct fixed31_32 c2 =
81 dc_fixpt_from_fraction(188515625, 10000000);
82 const struct fixed31_32 c3 =
83 dc_fixpt_from_fraction(186875, 10000);
84
85 struct fixed31_32 l_pow_m1;
86 struct fixed31_32 base;
87
88 if (dc_fixpt_lt(in_x, dc_fixpt_zero))
89 in_x = dc_fixpt_zero;
90
91 l_pow_m1 = dc_fixpt_pow(in_x, m1);
92 base = dc_fixpt_div(
93 dc_fixpt_add(c1,
94 (dc_fixpt_mul(c2, l_pow_m1))),
95 dc_fixpt_add(dc_fixpt_one,
96 (dc_fixpt_mul(c3, l_pow_m1))));
97 *out_y = dc_fixpt_pow(base, m2);
98 }
99
compute_de_pq(struct fixed31_32 in_x,struct fixed31_32 * out_y)100 static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
101 {
102 /* consts for dePQ gamma formula. */
103 const struct fixed31_32 m1 =
104 dc_fixpt_from_fraction(159301758, 1000000000);
105 const struct fixed31_32 m2 =
106 dc_fixpt_from_fraction(7884375, 100000);
107 const struct fixed31_32 c1 =
108 dc_fixpt_from_fraction(8359375, 10000000);
109 const struct fixed31_32 c2 =
110 dc_fixpt_from_fraction(188515625, 10000000);
111 const struct fixed31_32 c3 =
112 dc_fixpt_from_fraction(186875, 10000);
113
114 struct fixed31_32 l_pow_m1;
115 struct fixed31_32 base, div;
116
117
118 if (dc_fixpt_lt(in_x, dc_fixpt_zero))
119 in_x = dc_fixpt_zero;
120
121 l_pow_m1 = dc_fixpt_pow(in_x,
122 dc_fixpt_div(dc_fixpt_one, m2));
123 base = dc_fixpt_sub(l_pow_m1, c1);
124
125 if (dc_fixpt_lt(base, dc_fixpt_zero))
126 base = dc_fixpt_zero;
127
128 div = dc_fixpt_sub(c2, dc_fixpt_mul(c3, l_pow_m1));
129
130 *out_y = dc_fixpt_pow(dc_fixpt_div(base, div),
131 dc_fixpt_div(dc_fixpt_one, m1));
132
133 }
134
135 /*de gamma, none linear to linear*/
compute_hlg_oetf(struct fixed31_32 in_x,bool is_light0_12,struct fixed31_32 * out_y)136 static void compute_hlg_oetf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y)
137 {
138 struct fixed31_32 a;
139 struct fixed31_32 b;
140 struct fixed31_32 c;
141 struct fixed31_32 threshold;
142 struct fixed31_32 reference_white_level;
143
144 a = dc_fixpt_from_fraction(17883277, 100000000);
145 if (is_light0_12) {
146 /*light 0-12*/
147 b = dc_fixpt_from_fraction(28466892, 100000000);
148 c = dc_fixpt_from_fraction(55991073, 100000000);
149 threshold = dc_fixpt_one;
150 reference_white_level = dc_fixpt_half;
151 } else {
152 /*light 0-1*/
153 b = dc_fixpt_from_fraction(2372241, 100000000);
154 c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000));
155 threshold = dc_fixpt_from_fraction(1, 12);
156 reference_white_level = dc_fixpt_pow(dc_fixpt_from_fraction(3, 1), dc_fixpt_half);
157 }
158 if (dc_fixpt_lt(threshold, in_x))
159 *out_y = dc_fixpt_add(c, dc_fixpt_mul(a, dc_fixpt_log(dc_fixpt_sub(in_x, b))));
160 else
161 *out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_half), reference_white_level);
162 }
163
164 /*re gamma, linear to none linear*/
compute_hlg_eotf(struct fixed31_32 in_x,bool is_light0_12,struct fixed31_32 * out_y)165 static void compute_hlg_eotf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y)
166 {
167 struct fixed31_32 a;
168 struct fixed31_32 b;
169 struct fixed31_32 c;
170 struct fixed31_32 reference_white_level;
171
172 a = dc_fixpt_from_fraction(17883277, 100000000);
173 if (is_light0_12) {
174 /*light 0-12*/
175 b = dc_fixpt_from_fraction(28466892, 100000000);
176 c = dc_fixpt_from_fraction(55991073, 100000000);
177 reference_white_level = dc_fixpt_from_fraction(4, 1);
178 } else {
179 /*light 0-1*/
180 b = dc_fixpt_from_fraction(2372241, 100000000);
181 c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000));
182 reference_white_level = dc_fixpt_from_fraction(1, 3);
183 }
184 if (dc_fixpt_lt(dc_fixpt_half, in_x))
185 *out_y = dc_fixpt_add(dc_fixpt_exp(dc_fixpt_div(dc_fixpt_sub(in_x, c), a)), b);
186 else
187 *out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_from_fraction(2, 1)), reference_white_level);
188 }
189
190
191 /* one-time pre-compute PQ values - only for sdr_white_level 80 */
precompute_pq(void)192 void precompute_pq(void)
193 {
194 int i;
195 struct fixed31_32 x;
196 const struct hw_x_point *coord_x = coordinates_x + 32;
197 struct fixed31_32 scaling_factor =
198 dc_fixpt_from_fraction(80, 10000);
199
200 /* pow function has problems with arguments too small */
201 for (i = 0; i < 32; i++)
202 pq_table[i] = dc_fixpt_zero;
203
204 for (i = 32; i <= MAX_HW_POINTS; i++) {
205 x = dc_fixpt_mul(coord_x->x, scaling_factor);
206 compute_pq(x, &pq_table[i]);
207 ++coord_x;
208 }
209 }
210
211 /* one-time pre-compute dePQ values - only for max pixel value 125 FP16 */
precompute_de_pq(void)212 void precompute_de_pq(void)
213 {
214 int i;
215 struct fixed31_32 y;
216 uint32_t begin_index, end_index;
217
218 struct fixed31_32 scaling_factor = dc_fixpt_from_int(125);
219
220 /* X points is 2^-25 to 2^7
221 * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions
222 */
223 begin_index = 13 * NUM_PTS_IN_REGION;
224 end_index = begin_index + 12 * NUM_PTS_IN_REGION;
225
226 for (i = 0; i <= begin_index; i++)
227 de_pq_table[i] = dc_fixpt_zero;
228
229 for (; i <= end_index; i++) {
230 compute_de_pq(coordinates_x[i].x, &y);
231 de_pq_table[i] = dc_fixpt_mul(y, scaling_factor);
232 }
233
234 for (; i <= MAX_HW_POINTS; i++)
235 de_pq_table[i] = de_pq_table[i-1];
236 }
237 struct dividers {
238 struct fixed31_32 divider1;
239 struct fixed31_32 divider2;
240 struct fixed31_32 divider3;
241 };
242
build_coefficients(struct gamma_coefficients * coefficients,bool is_2_4)243 static void build_coefficients(struct gamma_coefficients *coefficients, bool is_2_4)
244 {
245 static const int32_t numerator01[] = { 31308, 180000};
246 static const int32_t numerator02[] = { 12920, 4500};
247 static const int32_t numerator03[] = { 55, 99};
248 static const int32_t numerator04[] = { 55, 99};
249 static const int32_t numerator05[] = { 2400, 2200};
250
251 uint32_t i = 0;
252 uint32_t index = is_2_4 == true ? 0:1;
253
254 do {
255 coefficients->a0[i] = dc_fixpt_from_fraction(
256 numerator01[index], 10000000);
257 coefficients->a1[i] = dc_fixpt_from_fraction(
258 numerator02[index], 1000);
259 coefficients->a2[i] = dc_fixpt_from_fraction(
260 numerator03[index], 1000);
261 coefficients->a3[i] = dc_fixpt_from_fraction(
262 numerator04[index], 1000);
263 coefficients->user_gamma[i] = dc_fixpt_from_fraction(
264 numerator05[index], 1000);
265
266 ++i;
267 } while (i != ARRAY_SIZE(coefficients->a0));
268 }
269
translate_from_linear_space(struct fixed31_32 arg,struct fixed31_32 a0,struct fixed31_32 a1,struct fixed31_32 a2,struct fixed31_32 a3,struct fixed31_32 gamma)270 static struct fixed31_32 translate_from_linear_space(
271 struct fixed31_32 arg,
272 struct fixed31_32 a0,
273 struct fixed31_32 a1,
274 struct fixed31_32 a2,
275 struct fixed31_32 a3,
276 struct fixed31_32 gamma)
277 {
278 const struct fixed31_32 one = dc_fixpt_from_int(1);
279
280 if (dc_fixpt_lt(one, arg))
281 return one;
282
283 if (dc_fixpt_le(arg, dc_fixpt_neg(a0)))
284 return dc_fixpt_sub(
285 a2,
286 dc_fixpt_mul(
287 dc_fixpt_add(
288 one,
289 a3),
290 dc_fixpt_pow(
291 dc_fixpt_neg(arg),
292 dc_fixpt_recip(gamma))));
293 else if (dc_fixpt_le(a0, arg))
294 return dc_fixpt_sub(
295 dc_fixpt_mul(
296 dc_fixpt_add(
297 one,
298 a3),
299 dc_fixpt_pow(
300 arg,
301 dc_fixpt_recip(gamma))),
302 a2);
303 else
304 return dc_fixpt_mul(
305 arg,
306 a1);
307 }
308
translate_to_linear_space(struct fixed31_32 arg,struct fixed31_32 a0,struct fixed31_32 a1,struct fixed31_32 a2,struct fixed31_32 a3,struct fixed31_32 gamma)309 static struct fixed31_32 translate_to_linear_space(
310 struct fixed31_32 arg,
311 struct fixed31_32 a0,
312 struct fixed31_32 a1,
313 struct fixed31_32 a2,
314 struct fixed31_32 a3,
315 struct fixed31_32 gamma)
316 {
317 struct fixed31_32 linear;
318
319 a0 = dc_fixpt_mul(a0, a1);
320 if (dc_fixpt_le(arg, dc_fixpt_neg(a0)))
321
322 linear = dc_fixpt_neg(
323 dc_fixpt_pow(
324 dc_fixpt_div(
325 dc_fixpt_sub(a2, arg),
326 dc_fixpt_add(
327 dc_fixpt_one, a3)), gamma));
328
329 else if (dc_fixpt_le(dc_fixpt_neg(a0), arg) &&
330 dc_fixpt_le(arg, a0))
331 linear = dc_fixpt_div(arg, a1);
332 else
333 linear = dc_fixpt_pow(
334 dc_fixpt_div(
335 dc_fixpt_add(a2, arg),
336 dc_fixpt_add(
337 dc_fixpt_one, a3)), gamma);
338
339 return linear;
340 }
341
translate_from_linear_space_ex(struct fixed31_32 arg,struct gamma_coefficients * coeff,uint32_t color_index)342 static inline struct fixed31_32 translate_from_linear_space_ex(
343 struct fixed31_32 arg,
344 struct gamma_coefficients *coeff,
345 uint32_t color_index)
346 {
347 return translate_from_linear_space(
348 arg,
349 coeff->a0[color_index],
350 coeff->a1[color_index],
351 coeff->a2[color_index],
352 coeff->a3[color_index],
353 coeff->user_gamma[color_index]);
354 }
355
356
translate_to_linear_space_ex(struct fixed31_32 arg,struct gamma_coefficients * coeff,uint32_t color_index)357 static inline struct fixed31_32 translate_to_linear_space_ex(
358 struct fixed31_32 arg,
359 struct gamma_coefficients *coeff,
360 uint32_t color_index)
361 {
362 return translate_to_linear_space(
363 arg,
364 coeff->a0[color_index],
365 coeff->a1[color_index],
366 coeff->a2[color_index],
367 coeff->a3[color_index],
368 coeff->user_gamma[color_index]);
369 }
370
371
find_software_points(const struct dc_gamma * ramp,const struct gamma_pixel * axis_x,struct fixed31_32 hw_point,enum channel_name channel,uint32_t * index_to_start,uint32_t * index_left,uint32_t * index_right,enum hw_point_position * pos)372 static bool find_software_points(
373 const struct dc_gamma *ramp,
374 const struct gamma_pixel *axis_x,
375 struct fixed31_32 hw_point,
376 enum channel_name channel,
377 uint32_t *index_to_start,
378 uint32_t *index_left,
379 uint32_t *index_right,
380 enum hw_point_position *pos)
381 {
382 const uint32_t max_number = ramp->num_entries + 3;
383
384 struct fixed31_32 left, right;
385
386 uint32_t i = *index_to_start;
387
388 while (i < max_number) {
389 if (channel == CHANNEL_NAME_RED) {
390 left = axis_x[i].r;
391
392 if (i < max_number - 1)
393 right = axis_x[i + 1].r;
394 else
395 right = axis_x[max_number - 1].r;
396 } else if (channel == CHANNEL_NAME_GREEN) {
397 left = axis_x[i].g;
398
399 if (i < max_number - 1)
400 right = axis_x[i + 1].g;
401 else
402 right = axis_x[max_number - 1].g;
403 } else {
404 left = axis_x[i].b;
405
406 if (i < max_number - 1)
407 right = axis_x[i + 1].b;
408 else
409 right = axis_x[max_number - 1].b;
410 }
411
412 if (dc_fixpt_le(left, hw_point) &&
413 dc_fixpt_le(hw_point, right)) {
414 *index_to_start = i;
415 *index_left = i;
416
417 if (i < max_number - 1)
418 *index_right = i + 1;
419 else
420 *index_right = max_number - 1;
421
422 *pos = HW_POINT_POSITION_MIDDLE;
423
424 return true;
425 } else if ((i == *index_to_start) &&
426 dc_fixpt_le(hw_point, left)) {
427 *index_to_start = i;
428 *index_left = i;
429 *index_right = i;
430
431 *pos = HW_POINT_POSITION_LEFT;
432
433 return true;
434 } else if ((i == max_number - 1) &&
435 dc_fixpt_le(right, hw_point)) {
436 *index_to_start = i;
437 *index_left = i;
438 *index_right = i;
439
440 *pos = HW_POINT_POSITION_RIGHT;
441
442 return true;
443 }
444
445 ++i;
446 }
447
448 return false;
449 }
450
build_custom_gamma_mapping_coefficients_worker(const struct dc_gamma * ramp,struct pixel_gamma_point * coeff,const struct hw_x_point * coordinates_x,const struct gamma_pixel * axis_x,enum channel_name channel,uint32_t number_of_points)451 static bool build_custom_gamma_mapping_coefficients_worker(
452 const struct dc_gamma *ramp,
453 struct pixel_gamma_point *coeff,
454 const struct hw_x_point *coordinates_x,
455 const struct gamma_pixel *axis_x,
456 enum channel_name channel,
457 uint32_t number_of_points)
458 {
459 uint32_t i = 0;
460
461 while (i <= number_of_points) {
462 struct fixed31_32 coord_x;
463
464 uint32_t index_to_start = 0;
465 uint32_t index_left = 0;
466 uint32_t index_right = 0;
467
468 enum hw_point_position hw_pos;
469
470 struct gamma_point *point;
471
472 struct fixed31_32 left_pos;
473 struct fixed31_32 right_pos;
474
475 if (channel == CHANNEL_NAME_RED)
476 coord_x = coordinates_x[i].regamma_y_red;
477 else if (channel == CHANNEL_NAME_GREEN)
478 coord_x = coordinates_x[i].regamma_y_green;
479 else
480 coord_x = coordinates_x[i].regamma_y_blue;
481
482 if (!find_software_points(
483 ramp, axis_x, coord_x, channel,
484 &index_to_start, &index_left, &index_right, &hw_pos)) {
485 BREAK_TO_DEBUGGER();
486 return false;
487 }
488
489 if (index_left >= ramp->num_entries + 3) {
490 BREAK_TO_DEBUGGER();
491 return false;
492 }
493
494 if (index_right >= ramp->num_entries + 3) {
495 BREAK_TO_DEBUGGER();
496 return false;
497 }
498
499 if (channel == CHANNEL_NAME_RED) {
500 point = &coeff[i].r;
501
502 left_pos = axis_x[index_left].r;
503 right_pos = axis_x[index_right].r;
504 } else if (channel == CHANNEL_NAME_GREEN) {
505 point = &coeff[i].g;
506
507 left_pos = axis_x[index_left].g;
508 right_pos = axis_x[index_right].g;
509 } else {
510 point = &coeff[i].b;
511
512 left_pos = axis_x[index_left].b;
513 right_pos = axis_x[index_right].b;
514 }
515
516 if (hw_pos == HW_POINT_POSITION_MIDDLE)
517 point->coeff = dc_fixpt_div(
518 dc_fixpt_sub(
519 coord_x,
520 left_pos),
521 dc_fixpt_sub(
522 right_pos,
523 left_pos));
524 else if (hw_pos == HW_POINT_POSITION_LEFT)
525 point->coeff = dc_fixpt_zero;
526 else if (hw_pos == HW_POINT_POSITION_RIGHT)
527 point->coeff = dc_fixpt_from_int(2);
528 else {
529 BREAK_TO_DEBUGGER();
530 return false;
531 }
532
533 point->left_index = index_left;
534 point->right_index = index_right;
535 point->pos = hw_pos;
536
537 ++i;
538 }
539
540 return true;
541 }
542
calculate_mapped_value(struct pwl_float_data * rgb,const struct pixel_gamma_point * coeff,enum channel_name channel,uint32_t max_index)543 static struct fixed31_32 calculate_mapped_value(
544 struct pwl_float_data *rgb,
545 const struct pixel_gamma_point *coeff,
546 enum channel_name channel,
547 uint32_t max_index)
548 {
549 const struct gamma_point *point;
550
551 struct fixed31_32 result;
552
553 if (channel == CHANNEL_NAME_RED)
554 point = &coeff->r;
555 else if (channel == CHANNEL_NAME_GREEN)
556 point = &coeff->g;
557 else
558 point = &coeff->b;
559
560 if ((point->left_index < 0) || (point->left_index > max_index)) {
561 BREAK_TO_DEBUGGER();
562 return dc_fixpt_zero;
563 }
564
565 if ((point->right_index < 0) || (point->right_index > max_index)) {
566 BREAK_TO_DEBUGGER();
567 return dc_fixpt_zero;
568 }
569
570 if (point->pos == HW_POINT_POSITION_MIDDLE)
571 if (channel == CHANNEL_NAME_RED)
572 result = dc_fixpt_add(
573 dc_fixpt_mul(
574 point->coeff,
575 dc_fixpt_sub(
576 rgb[point->right_index].r,
577 rgb[point->left_index].r)),
578 rgb[point->left_index].r);
579 else if (channel == CHANNEL_NAME_GREEN)
580 result = dc_fixpt_add(
581 dc_fixpt_mul(
582 point->coeff,
583 dc_fixpt_sub(
584 rgb[point->right_index].g,
585 rgb[point->left_index].g)),
586 rgb[point->left_index].g);
587 else
588 result = dc_fixpt_add(
589 dc_fixpt_mul(
590 point->coeff,
591 dc_fixpt_sub(
592 rgb[point->right_index].b,
593 rgb[point->left_index].b)),
594 rgb[point->left_index].b);
595 else if (point->pos == HW_POINT_POSITION_LEFT) {
596 BREAK_TO_DEBUGGER();
597 result = dc_fixpt_zero;
598 } else {
599 BREAK_TO_DEBUGGER();
600 result = dc_fixpt_one;
601 }
602
603 return result;
604 }
605
build_pq(struct pwl_float_data_ex * rgb_regamma,uint32_t hw_points_num,const struct hw_x_point * coordinate_x,uint32_t sdr_white_level)606 static void build_pq(struct pwl_float_data_ex *rgb_regamma,
607 uint32_t hw_points_num,
608 const struct hw_x_point *coordinate_x,
609 uint32_t sdr_white_level)
610 {
611 uint32_t i, start_index;
612
613 struct pwl_float_data_ex *rgb = rgb_regamma;
614 const struct hw_x_point *coord_x = coordinate_x;
615 struct fixed31_32 x;
616 struct fixed31_32 output;
617 struct fixed31_32 scaling_factor =
618 dc_fixpt_from_fraction(sdr_white_level, 10000);
619
620 if (!pq_initialized && sdr_white_level == 80) {
621 precompute_pq();
622 pq_initialized = true;
623 }
624
625 /* TODO: start index is from segment 2^-24, skipping first segment
626 * due to x values too small for power calculations
627 */
628 start_index = 32;
629 rgb += start_index;
630 coord_x += start_index;
631
632 for (i = start_index; i <= hw_points_num; i++) {
633 /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125.
634 * FP 1.0 = 80nits
635 */
636 if (sdr_white_level == 80) {
637 output = pq_table[i];
638 } else {
639 x = dc_fixpt_mul(coord_x->x, scaling_factor);
640 compute_pq(x, &output);
641 }
642
643 /* should really not happen? */
644 if (dc_fixpt_lt(output, dc_fixpt_zero))
645 output = dc_fixpt_zero;
646 else if (dc_fixpt_lt(dc_fixpt_one, output))
647 output = dc_fixpt_one;
648
649 rgb->r = output;
650 rgb->g = output;
651 rgb->b = output;
652
653 ++coord_x;
654 ++rgb;
655 }
656 }
657
build_de_pq(struct pwl_float_data_ex * de_pq,uint32_t hw_points_num,const struct hw_x_point * coordinate_x)658 static void build_de_pq(struct pwl_float_data_ex *de_pq,
659 uint32_t hw_points_num,
660 const struct hw_x_point *coordinate_x)
661 {
662 uint32_t i;
663 struct fixed31_32 output;
664
665 struct fixed31_32 scaling_factor = dc_fixpt_from_int(125);
666
667 if (!de_pq_initialized) {
668 precompute_de_pq();
669 de_pq_initialized = true;
670 }
671
672
673 for (i = 0; i <= hw_points_num; i++) {
674 output = de_pq_table[i];
675 /* should really not happen? */
676 if (dc_fixpt_lt(output, dc_fixpt_zero))
677 output = dc_fixpt_zero;
678 else if (dc_fixpt_lt(scaling_factor, output))
679 output = scaling_factor;
680 de_pq[i].r = output;
681 de_pq[i].g = output;
682 de_pq[i].b = output;
683 }
684 }
685
build_regamma(struct pwl_float_data_ex * rgb_regamma,uint32_t hw_points_num,const struct hw_x_point * coordinate_x,bool is_2_4)686 static void build_regamma(struct pwl_float_data_ex *rgb_regamma,
687 uint32_t hw_points_num,
688 const struct hw_x_point *coordinate_x, bool is_2_4)
689 {
690 uint32_t i;
691
692 struct gamma_coefficients coeff;
693 struct pwl_float_data_ex *rgb = rgb_regamma;
694 const struct hw_x_point *coord_x = coordinate_x;
695
696 build_coefficients(&coeff, is_2_4);
697
698 i = 0;
699
700 while (i != hw_points_num + 1) {
701 /*TODO use y vs r,g,b*/
702 rgb->r = translate_from_linear_space_ex(
703 coord_x->x, &coeff, 0);
704 rgb->g = rgb->r;
705 rgb->b = rgb->r;
706 ++coord_x;
707 ++rgb;
708 ++i;
709 }
710 }
711
build_degamma(struct pwl_float_data_ex * curve,uint32_t hw_points_num,const struct hw_x_point * coordinate_x,bool is_2_4)712 static void build_degamma(struct pwl_float_data_ex *curve,
713 uint32_t hw_points_num,
714 const struct hw_x_point *coordinate_x, bool is_2_4)
715 {
716 uint32_t i;
717 struct gamma_coefficients coeff;
718 uint32_t begin_index, end_index;
719
720 build_coefficients(&coeff, is_2_4);
721 i = 0;
722
723 /* X points is 2^-25 to 2^7
724 * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions
725 */
726 begin_index = 13 * NUM_PTS_IN_REGION;
727 end_index = begin_index + 12 * NUM_PTS_IN_REGION;
728
729 while (i != begin_index) {
730 curve[i].r = dc_fixpt_zero;
731 curve[i].g = dc_fixpt_zero;
732 curve[i].b = dc_fixpt_zero;
733 i++;
734 }
735
736 while (i != end_index) {
737 curve[i].r = translate_to_linear_space_ex(
738 coordinate_x[i].x, &coeff, 0);
739 curve[i].g = curve[i].r;
740 curve[i].b = curve[i].r;
741 i++;
742 }
743 while (i != hw_points_num + 1) {
744 curve[i].r = dc_fixpt_one;
745 curve[i].g = dc_fixpt_one;
746 curve[i].b = dc_fixpt_one;
747 i++;
748 }
749 }
750
build_hlg_degamma(struct pwl_float_data_ex * degamma,uint32_t hw_points_num,const struct hw_x_point * coordinate_x,bool is_light0_12)751 static void build_hlg_degamma(struct pwl_float_data_ex *degamma,
752 uint32_t hw_points_num,
753 const struct hw_x_point *coordinate_x, bool is_light0_12)
754 {
755 uint32_t i;
756
757 struct pwl_float_data_ex *rgb = degamma;
758 const struct hw_x_point *coord_x = coordinate_x;
759
760 i = 0;
761
762 while (i != hw_points_num + 1) {
763 compute_hlg_oetf(coord_x->x, is_light0_12, &rgb->r);
764 rgb->g = rgb->r;
765 rgb->b = rgb->r;
766 ++coord_x;
767 ++rgb;
768 ++i;
769 }
770 }
771
build_hlg_regamma(struct pwl_float_data_ex * regamma,uint32_t hw_points_num,const struct hw_x_point * coordinate_x,bool is_light0_12)772 static void build_hlg_regamma(struct pwl_float_data_ex *regamma,
773 uint32_t hw_points_num,
774 const struct hw_x_point *coordinate_x, bool is_light0_12)
775 {
776 uint32_t i;
777
778 struct pwl_float_data_ex *rgb = regamma;
779 const struct hw_x_point *coord_x = coordinate_x;
780
781 i = 0;
782
783 while (i != hw_points_num + 1) {
784 compute_hlg_eotf(coord_x->x, is_light0_12, &rgb->r);
785 rgb->g = rgb->r;
786 rgb->b = rgb->r;
787 ++coord_x;
788 ++rgb;
789 ++i;
790 }
791 }
792
scale_gamma(struct pwl_float_data * pwl_rgb,const struct dc_gamma * ramp,struct dividers dividers)793 static void scale_gamma(struct pwl_float_data *pwl_rgb,
794 const struct dc_gamma *ramp,
795 struct dividers dividers)
796 {
797 const struct fixed31_32 max_driver = dc_fixpt_from_int(0xFFFF);
798 const struct fixed31_32 max_os = dc_fixpt_from_int(0xFF00);
799 struct fixed31_32 scaler = max_os;
800 uint32_t i;
801 struct pwl_float_data *rgb = pwl_rgb;
802 struct pwl_float_data *rgb_last = rgb + ramp->num_entries - 1;
803
804 i = 0;
805
806 do {
807 if (dc_fixpt_lt(max_os, ramp->entries.red[i]) ||
808 dc_fixpt_lt(max_os, ramp->entries.green[i]) ||
809 dc_fixpt_lt(max_os, ramp->entries.blue[i])) {
810 scaler = max_driver;
811 break;
812 }
813 ++i;
814 } while (i != ramp->num_entries);
815
816 i = 0;
817
818 do {
819 rgb->r = dc_fixpt_div(
820 ramp->entries.red[i], scaler);
821 rgb->g = dc_fixpt_div(
822 ramp->entries.green[i], scaler);
823 rgb->b = dc_fixpt_div(
824 ramp->entries.blue[i], scaler);
825
826 ++rgb;
827 ++i;
828 } while (i != ramp->num_entries);
829
830 rgb->r = dc_fixpt_mul(rgb_last->r,
831 dividers.divider1);
832 rgb->g = dc_fixpt_mul(rgb_last->g,
833 dividers.divider1);
834 rgb->b = dc_fixpt_mul(rgb_last->b,
835 dividers.divider1);
836
837 ++rgb;
838
839 rgb->r = dc_fixpt_mul(rgb_last->r,
840 dividers.divider2);
841 rgb->g = dc_fixpt_mul(rgb_last->g,
842 dividers.divider2);
843 rgb->b = dc_fixpt_mul(rgb_last->b,
844 dividers.divider2);
845
846 ++rgb;
847
848 rgb->r = dc_fixpt_mul(rgb_last->r,
849 dividers.divider3);
850 rgb->g = dc_fixpt_mul(rgb_last->g,
851 dividers.divider3);
852 rgb->b = dc_fixpt_mul(rgb_last->b,
853 dividers.divider3);
854 }
855
scale_gamma_dx(struct pwl_float_data * pwl_rgb,const struct dc_gamma * ramp,struct dividers dividers)856 static void scale_gamma_dx(struct pwl_float_data *pwl_rgb,
857 const struct dc_gamma *ramp,
858 struct dividers dividers)
859 {
860 uint32_t i;
861 struct fixed31_32 min = dc_fixpt_zero;
862 struct fixed31_32 max = dc_fixpt_one;
863
864 struct fixed31_32 delta = dc_fixpt_zero;
865 struct fixed31_32 offset = dc_fixpt_zero;
866
867 for (i = 0 ; i < ramp->num_entries; i++) {
868 if (dc_fixpt_lt(ramp->entries.red[i], min))
869 min = ramp->entries.red[i];
870
871 if (dc_fixpt_lt(ramp->entries.green[i], min))
872 min = ramp->entries.green[i];
873
874 if (dc_fixpt_lt(ramp->entries.blue[i], min))
875 min = ramp->entries.blue[i];
876
877 if (dc_fixpt_lt(max, ramp->entries.red[i]))
878 max = ramp->entries.red[i];
879
880 if (dc_fixpt_lt(max, ramp->entries.green[i]))
881 max = ramp->entries.green[i];
882
883 if (dc_fixpt_lt(max, ramp->entries.blue[i]))
884 max = ramp->entries.blue[i];
885 }
886
887 if (dc_fixpt_lt(min, dc_fixpt_zero))
888 delta = dc_fixpt_neg(min);
889
890 offset = dc_fixpt_add(min, max);
891
892 for (i = 0 ; i < ramp->num_entries; i++) {
893 pwl_rgb[i].r = dc_fixpt_div(
894 dc_fixpt_add(
895 ramp->entries.red[i], delta), offset);
896 pwl_rgb[i].g = dc_fixpt_div(
897 dc_fixpt_add(
898 ramp->entries.green[i], delta), offset);
899 pwl_rgb[i].b = dc_fixpt_div(
900 dc_fixpt_add(
901 ramp->entries.blue[i], delta), offset);
902
903 }
904
905 pwl_rgb[i].r = dc_fixpt_sub(dc_fixpt_mul_int(
906 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
907 pwl_rgb[i].g = dc_fixpt_sub(dc_fixpt_mul_int(
908 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
909 pwl_rgb[i].b = dc_fixpt_sub(dc_fixpt_mul_int(
910 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
911 ++i;
912 pwl_rgb[i].r = dc_fixpt_sub(dc_fixpt_mul_int(
913 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
914 pwl_rgb[i].g = dc_fixpt_sub(dc_fixpt_mul_int(
915 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
916 pwl_rgb[i].b = dc_fixpt_sub(dc_fixpt_mul_int(
917 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
918 }
919
920 /* todo: all these scale_gamma functions are inherently the same but
921 * take different structures as params or different format for ramp
922 * values. We could probably implement it in a more generic fashion
923 */
scale_user_regamma_ramp(struct pwl_float_data * pwl_rgb,const struct regamma_ramp * ramp,struct dividers dividers)924 static void scale_user_regamma_ramp(struct pwl_float_data *pwl_rgb,
925 const struct regamma_ramp *ramp,
926 struct dividers dividers)
927 {
928 unsigned short max_driver = 0xFFFF;
929 unsigned short max_os = 0xFF00;
930 unsigned short scaler = max_os;
931 uint32_t i;
932 struct pwl_float_data *rgb = pwl_rgb;
933 struct pwl_float_data *rgb_last = rgb + GAMMA_RGB_256_ENTRIES - 1;
934
935 i = 0;
936 do {
937 if (ramp->gamma[i] > max_os ||
938 ramp->gamma[i + 256] > max_os ||
939 ramp->gamma[i + 512] > max_os) {
940 scaler = max_driver;
941 break;
942 }
943 i++;
944 } while (i != GAMMA_RGB_256_ENTRIES);
945
946 i = 0;
947 do {
948 rgb->r = dc_fixpt_from_fraction(
949 ramp->gamma[i], scaler);
950 rgb->g = dc_fixpt_from_fraction(
951 ramp->gamma[i + 256], scaler);
952 rgb->b = dc_fixpt_from_fraction(
953 ramp->gamma[i + 512], scaler);
954
955 ++rgb;
956 ++i;
957 } while (i != GAMMA_RGB_256_ENTRIES);
958
959 rgb->r = dc_fixpt_mul(rgb_last->r,
960 dividers.divider1);
961 rgb->g = dc_fixpt_mul(rgb_last->g,
962 dividers.divider1);
963 rgb->b = dc_fixpt_mul(rgb_last->b,
964 dividers.divider1);
965
966 ++rgb;
967
968 rgb->r = dc_fixpt_mul(rgb_last->r,
969 dividers.divider2);
970 rgb->g = dc_fixpt_mul(rgb_last->g,
971 dividers.divider2);
972 rgb->b = dc_fixpt_mul(rgb_last->b,
973 dividers.divider2);
974
975 ++rgb;
976
977 rgb->r = dc_fixpt_mul(rgb_last->r,
978 dividers.divider3);
979 rgb->g = dc_fixpt_mul(rgb_last->g,
980 dividers.divider3);
981 rgb->b = dc_fixpt_mul(rgb_last->b,
982 dividers.divider3);
983 }
984
985 /*
986 * RS3+ color transform DDI - 1D LUT adjustment is composed with regamma here
987 * Input is evenly distributed in the output color space as specified in
988 * SetTimings
989 *
990 * Interpolation details:
991 * 1D LUT has 4096 values which give curve correction in 0-1 float range
992 * for evenly spaced points in 0-1 range. lut1D[index] gives correction
993 * for index/4095.
994 * First we find index for which:
995 * index/4095 < regamma_y < (index+1)/4095 =>
996 * index < 4095*regamma_y < index + 1
997 * norm_y = 4095*regamma_y, and index is just truncating to nearest integer
998 * lut1 = lut1D[index], lut2 = lut1D[index+1]
999 *
1000 * adjustedY is then linearly interpolating regamma Y between lut1 and lut2
1001 *
1002 * Custom degamma on Linux uses the same interpolation math, so is handled here
1003 */
apply_lut_1d(const struct dc_gamma * ramp,uint32_t num_hw_points,struct dc_transfer_func_distributed_points * tf_pts)1004 static void apply_lut_1d(
1005 const struct dc_gamma *ramp,
1006 uint32_t num_hw_points,
1007 struct dc_transfer_func_distributed_points *tf_pts)
1008 {
1009 int i = 0;
1010 int color = 0;
1011 struct fixed31_32 *regamma_y;
1012 struct fixed31_32 norm_y;
1013 struct fixed31_32 lut1;
1014 struct fixed31_32 lut2;
1015 const int max_lut_index = 4095;
1016 const struct fixed31_32 max_lut_index_f =
1017 dc_fixpt_from_int(max_lut_index);
1018 int32_t index = 0, index_next = 0;
1019 struct fixed31_32 index_f;
1020 struct fixed31_32 delta_lut;
1021 struct fixed31_32 delta_index;
1022
1023 if (ramp->type != GAMMA_CS_TFM_1D && ramp->type != GAMMA_CUSTOM)
1024 return; // this is not expected
1025
1026 for (i = 0; i < num_hw_points; i++) {
1027 for (color = 0; color < 3; color++) {
1028 if (color == 0)
1029 regamma_y = &tf_pts->red[i];
1030 else if (color == 1)
1031 regamma_y = &tf_pts->green[i];
1032 else
1033 regamma_y = &tf_pts->blue[i];
1034
1035 norm_y = dc_fixpt_mul(max_lut_index_f,
1036 *regamma_y);
1037 index = dc_fixpt_floor(norm_y);
1038 index_f = dc_fixpt_from_int(index);
1039
1040 if (index < 0 || index > max_lut_index)
1041 continue;
1042
1043 index_next = (index == max_lut_index) ? index : index+1;
1044
1045 if (color == 0) {
1046 lut1 = ramp->entries.red[index];
1047 lut2 = ramp->entries.red[index_next];
1048 } else if (color == 1) {
1049 lut1 = ramp->entries.green[index];
1050 lut2 = ramp->entries.green[index_next];
1051 } else {
1052 lut1 = ramp->entries.blue[index];
1053 lut2 = ramp->entries.blue[index_next];
1054 }
1055
1056 // we have everything now, so interpolate
1057 delta_lut = dc_fixpt_sub(lut2, lut1);
1058 delta_index = dc_fixpt_sub(norm_y, index_f);
1059
1060 *regamma_y = dc_fixpt_add(lut1,
1061 dc_fixpt_mul(delta_index, delta_lut));
1062 }
1063 }
1064 }
1065
build_evenly_distributed_points(struct gamma_pixel * points,uint32_t numberof_points,struct dividers dividers)1066 static void build_evenly_distributed_points(
1067 struct gamma_pixel *points,
1068 uint32_t numberof_points,
1069 struct dividers dividers)
1070 {
1071 struct gamma_pixel *p = points;
1072 struct gamma_pixel *p_last;
1073
1074 uint32_t i = 0;
1075
1076 // This function should not gets called with 0 as a parameter
1077 ASSERT(numberof_points > 0);
1078 p_last = p + numberof_points - 1;
1079
1080 do {
1081 struct fixed31_32 value = dc_fixpt_from_fraction(i,
1082 numberof_points - 1);
1083
1084 p->r = value;
1085 p->g = value;
1086 p->b = value;
1087
1088 ++p;
1089 ++i;
1090 } while (i < numberof_points);
1091
1092 p->r = dc_fixpt_div(p_last->r, dividers.divider1);
1093 p->g = dc_fixpt_div(p_last->g, dividers.divider1);
1094 p->b = dc_fixpt_div(p_last->b, dividers.divider1);
1095
1096 ++p;
1097
1098 p->r = dc_fixpt_div(p_last->r, dividers.divider2);
1099 p->g = dc_fixpt_div(p_last->g, dividers.divider2);
1100 p->b = dc_fixpt_div(p_last->b, dividers.divider2);
1101
1102 ++p;
1103
1104 p->r = dc_fixpt_div(p_last->r, dividers.divider3);
1105 p->g = dc_fixpt_div(p_last->g, dividers.divider3);
1106 p->b = dc_fixpt_div(p_last->b, dividers.divider3);
1107 }
1108
copy_rgb_regamma_to_coordinates_x(struct hw_x_point * coordinates_x,uint32_t hw_points_num,const struct pwl_float_data_ex * rgb_ex)1109 static inline void copy_rgb_regamma_to_coordinates_x(
1110 struct hw_x_point *coordinates_x,
1111 uint32_t hw_points_num,
1112 const struct pwl_float_data_ex *rgb_ex)
1113 {
1114 struct hw_x_point *coords = coordinates_x;
1115 uint32_t i = 0;
1116 const struct pwl_float_data_ex *rgb_regamma = rgb_ex;
1117
1118 while (i <= hw_points_num + 1) {
1119 coords->regamma_y_red = rgb_regamma->r;
1120 coords->regamma_y_green = rgb_regamma->g;
1121 coords->regamma_y_blue = rgb_regamma->b;
1122
1123 ++coords;
1124 ++rgb_regamma;
1125 ++i;
1126 }
1127 }
1128
calculate_interpolated_hardware_curve(const struct dc_gamma * ramp,struct pixel_gamma_point * coeff128,struct pwl_float_data * rgb_user,const struct hw_x_point * coordinates_x,const struct gamma_pixel * axis_x,uint32_t number_of_points,struct dc_transfer_func_distributed_points * tf_pts)1129 static bool calculate_interpolated_hardware_curve(
1130 const struct dc_gamma *ramp,
1131 struct pixel_gamma_point *coeff128,
1132 struct pwl_float_data *rgb_user,
1133 const struct hw_x_point *coordinates_x,
1134 const struct gamma_pixel *axis_x,
1135 uint32_t number_of_points,
1136 struct dc_transfer_func_distributed_points *tf_pts)
1137 {
1138
1139 const struct pixel_gamma_point *coeff = coeff128;
1140 uint32_t max_entries = 3 - 1;
1141
1142 uint32_t i = 0;
1143
1144 for (i = 0; i < 3; i++) {
1145 if (!build_custom_gamma_mapping_coefficients_worker(
1146 ramp, coeff128, coordinates_x, axis_x, i,
1147 number_of_points))
1148 return false;
1149 }
1150
1151 i = 0;
1152 max_entries += ramp->num_entries;
1153
1154 /* TODO: float point case */
1155
1156 while (i <= number_of_points) {
1157 tf_pts->red[i] = calculate_mapped_value(
1158 rgb_user, coeff, CHANNEL_NAME_RED, max_entries);
1159 tf_pts->green[i] = calculate_mapped_value(
1160 rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries);
1161 tf_pts->blue[i] = calculate_mapped_value(
1162 rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries);
1163
1164 ++coeff;
1165 ++i;
1166 }
1167
1168 return true;
1169 }
1170
1171 /* The "old" interpolation uses a complicated scheme to build an array of
1172 * coefficients while also using an array of 0-255 normalized to 0-1
1173 * Then there's another loop using both of the above + new scaled user ramp
1174 * and we concatenate them. It also searches for points of interpolation and
1175 * uses enums for positions.
1176 *
1177 * This function uses a different approach:
1178 * user ramp is always applied on X with 0/255, 1/255, 2/255, ..., 255/255
1179 * To find index for hwX , we notice the following:
1180 * i/255 <= hwX < (i+1)/255 <=> i <= 255*hwX < i+1
1181 * See apply_lut_1d which is the same principle, but on 4K entry 1D LUT
1182 *
1183 * Once the index is known, combined Y is simply:
1184 * user_ramp(index) + (hwX-index/255)*(user_ramp(index+1) - user_ramp(index)
1185 *
1186 * We should switch to this method in all cases, it's simpler and faster
1187 * ToDo one day - for now this only applies to ADL regamma to avoid regression
1188 * for regular use cases (sRGB and PQ)
1189 */
interpolate_user_regamma(uint32_t hw_points_num,struct pwl_float_data * rgb_user,bool apply_degamma,struct dc_transfer_func_distributed_points * tf_pts)1190 static void interpolate_user_regamma(uint32_t hw_points_num,
1191 struct pwl_float_data *rgb_user,
1192 bool apply_degamma,
1193 struct dc_transfer_func_distributed_points *tf_pts)
1194 {
1195 uint32_t i;
1196 uint32_t color = 0;
1197 int32_t index;
1198 int32_t index_next;
1199 struct fixed31_32 *tf_point;
1200 struct fixed31_32 hw_x;
1201 struct fixed31_32 norm_factor =
1202 dc_fixpt_from_int(255);
1203 struct fixed31_32 norm_x;
1204 struct fixed31_32 index_f;
1205 struct fixed31_32 lut1;
1206 struct fixed31_32 lut2;
1207 struct fixed31_32 delta_lut;
1208 struct fixed31_32 delta_index;
1209
1210 i = 0;
1211 /* fixed_pt library has problems handling too small values */
1212 while (i != 32) {
1213 tf_pts->red[i] = dc_fixpt_zero;
1214 tf_pts->green[i] = dc_fixpt_zero;
1215 tf_pts->blue[i] = dc_fixpt_zero;
1216 ++i;
1217 }
1218 while (i <= hw_points_num + 1) {
1219 for (color = 0; color < 3; color++) {
1220 if (color == 0)
1221 tf_point = &tf_pts->red[i];
1222 else if (color == 1)
1223 tf_point = &tf_pts->green[i];
1224 else
1225 tf_point = &tf_pts->blue[i];
1226
1227 if (apply_degamma) {
1228 if (color == 0)
1229 hw_x = coordinates_x[i].regamma_y_red;
1230 else if (color == 1)
1231 hw_x = coordinates_x[i].regamma_y_green;
1232 else
1233 hw_x = coordinates_x[i].regamma_y_blue;
1234 } else
1235 hw_x = coordinates_x[i].x;
1236
1237 norm_x = dc_fixpt_mul(norm_factor, hw_x);
1238 index = dc_fixpt_floor(norm_x);
1239 if (index < 0 || index > 255)
1240 continue;
1241
1242 index_f = dc_fixpt_from_int(index);
1243 index_next = (index == 255) ? index : index + 1;
1244
1245 if (color == 0) {
1246 lut1 = rgb_user[index].r;
1247 lut2 = rgb_user[index_next].r;
1248 } else if (color == 1) {
1249 lut1 = rgb_user[index].g;
1250 lut2 = rgb_user[index_next].g;
1251 } else {
1252 lut1 = rgb_user[index].b;
1253 lut2 = rgb_user[index_next].b;
1254 }
1255
1256 // we have everything now, so interpolate
1257 delta_lut = dc_fixpt_sub(lut2, lut1);
1258 delta_index = dc_fixpt_sub(norm_x, index_f);
1259
1260 *tf_point = dc_fixpt_add(lut1,
1261 dc_fixpt_mul(delta_index, delta_lut));
1262 }
1263 ++i;
1264 }
1265 }
1266
build_new_custom_resulted_curve(uint32_t hw_points_num,struct dc_transfer_func_distributed_points * tf_pts)1267 static void build_new_custom_resulted_curve(
1268 uint32_t hw_points_num,
1269 struct dc_transfer_func_distributed_points *tf_pts)
1270 {
1271 uint32_t i;
1272
1273 i = 0;
1274
1275 while (i != hw_points_num + 1) {
1276 tf_pts->red[i] = dc_fixpt_clamp(
1277 tf_pts->red[i], dc_fixpt_zero,
1278 dc_fixpt_one);
1279 tf_pts->green[i] = dc_fixpt_clamp(
1280 tf_pts->green[i], dc_fixpt_zero,
1281 dc_fixpt_one);
1282 tf_pts->blue[i] = dc_fixpt_clamp(
1283 tf_pts->blue[i], dc_fixpt_zero,
1284 dc_fixpt_one);
1285
1286 ++i;
1287 }
1288 }
1289
apply_degamma_for_user_regamma(struct pwl_float_data_ex * rgb_regamma,uint32_t hw_points_num)1290 static void apply_degamma_for_user_regamma(struct pwl_float_data_ex *rgb_regamma,
1291 uint32_t hw_points_num)
1292 {
1293 uint32_t i;
1294
1295 struct gamma_coefficients coeff;
1296 struct pwl_float_data_ex *rgb = rgb_regamma;
1297 const struct hw_x_point *coord_x = coordinates_x;
1298
1299 build_coefficients(&coeff, true);
1300
1301 i = 0;
1302 while (i != hw_points_num + 1) {
1303 rgb->r = translate_from_linear_space_ex(
1304 coord_x->x, &coeff, 0);
1305 rgb->g = rgb->r;
1306 rgb->b = rgb->r;
1307 ++coord_x;
1308 ++rgb;
1309 ++i;
1310 }
1311 }
1312
map_regamma_hw_to_x_user(const struct dc_gamma * ramp,struct pixel_gamma_point * coeff128,struct pwl_float_data * rgb_user,struct hw_x_point * coords_x,const struct gamma_pixel * axis_x,const struct pwl_float_data_ex * rgb_regamma,uint32_t hw_points_num,struct dc_transfer_func_distributed_points * tf_pts,bool mapUserRamp)1313 static bool map_regamma_hw_to_x_user(
1314 const struct dc_gamma *ramp,
1315 struct pixel_gamma_point *coeff128,
1316 struct pwl_float_data *rgb_user,
1317 struct hw_x_point *coords_x,
1318 const struct gamma_pixel *axis_x,
1319 const struct pwl_float_data_ex *rgb_regamma,
1320 uint32_t hw_points_num,
1321 struct dc_transfer_func_distributed_points *tf_pts,
1322 bool mapUserRamp)
1323 {
1324 /* setup to spare calculated ideal regamma values */
1325
1326 int i = 0;
1327 struct hw_x_point *coords = coords_x;
1328 const struct pwl_float_data_ex *regamma = rgb_regamma;
1329
1330 if (mapUserRamp) {
1331 copy_rgb_regamma_to_coordinates_x(coords,
1332 hw_points_num,
1333 rgb_regamma);
1334
1335 calculate_interpolated_hardware_curve(
1336 ramp, coeff128, rgb_user, coords, axis_x,
1337 hw_points_num, tf_pts);
1338 } else {
1339 /* just copy current rgb_regamma into tf_pts */
1340 while (i <= hw_points_num) {
1341 tf_pts->red[i] = regamma->r;
1342 tf_pts->green[i] = regamma->g;
1343 tf_pts->blue[i] = regamma->b;
1344
1345 ++regamma;
1346 ++i;
1347 }
1348 }
1349
1350 /* this should be named differently, all it does is clamp to 0-1 */
1351 build_new_custom_resulted_curve(hw_points_num, tf_pts);
1352
1353 return true;
1354 }
1355
1356 #define _EXTRA_POINTS 3
1357
mod_color_calculate_regamma_params(struct dc_transfer_func * output_tf,const struct dc_gamma * ramp,bool mapUserRamp)1358 bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
1359 const struct dc_gamma *ramp, bool mapUserRamp)
1360 {
1361 struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
1362 struct dividers dividers;
1363
1364 struct pwl_float_data *rgb_user = NULL;
1365 struct pwl_float_data_ex *rgb_regamma = NULL;
1366 struct gamma_pixel *axix_x = NULL;
1367 struct pixel_gamma_point *coeff = NULL;
1368 enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1369 bool ret = false;
1370
1371 if (output_tf->type == TF_TYPE_BYPASS)
1372 return false;
1373
1374 /* we can use hardcoded curve for plain SRGB TF */
1375 if (output_tf->type == TF_TYPE_PREDEFINED &&
1376 output_tf->tf == TRANSFER_FUNCTION_SRGB &&
1377 (!mapUserRamp && ramp->type == GAMMA_RGB_256))
1378 return true;
1379
1380 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1381
1382 rgb_user = kcalloc(ramp->num_entries + _EXTRA_POINTS,
1383 sizeof(*rgb_user),
1384 GFP_KERNEL);
1385 if (!rgb_user)
1386 goto rgb_user_alloc_fail;
1387 rgb_regamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1388 sizeof(*rgb_regamma),
1389 GFP_KERNEL);
1390 if (!rgb_regamma)
1391 goto rgb_regamma_alloc_fail;
1392 axix_x = kcalloc(ramp->num_entries + 3, sizeof(*axix_x),
1393 GFP_KERNEL);
1394 if (!axix_x)
1395 goto axix_x_alloc_fail;
1396 coeff = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff),
1397 GFP_KERNEL);
1398 if (!coeff)
1399 goto coeff_alloc_fail;
1400
1401 dividers.divider1 = dc_fixpt_from_fraction(3, 2);
1402 dividers.divider2 = dc_fixpt_from_int(2);
1403 dividers.divider3 = dc_fixpt_from_fraction(5, 2);
1404
1405 tf = output_tf->tf;
1406
1407 build_evenly_distributed_points(
1408 axix_x,
1409 ramp->num_entries,
1410 dividers);
1411
1412 if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
1413 scale_gamma(rgb_user, ramp, dividers);
1414 else if (ramp->type == GAMMA_RGB_FLOAT_1024)
1415 scale_gamma_dx(rgb_user, ramp, dividers);
1416
1417 if (tf == TRANSFER_FUNCTION_PQ) {
1418 tf_pts->end_exponent = 7;
1419 tf_pts->x_point_at_y1_red = 125;
1420 tf_pts->x_point_at_y1_green = 125;
1421 tf_pts->x_point_at_y1_blue = 125;
1422
1423 build_pq(rgb_regamma,
1424 MAX_HW_POINTS,
1425 coordinates_x,
1426 output_tf->sdr_ref_white_level);
1427 } else {
1428 tf_pts->end_exponent = 0;
1429 tf_pts->x_point_at_y1_red = 1;
1430 tf_pts->x_point_at_y1_green = 1;
1431 tf_pts->x_point_at_y1_blue = 1;
1432
1433 build_regamma(rgb_regamma,
1434 MAX_HW_POINTS,
1435 coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? true:false);
1436 }
1437
1438 map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1439 coordinates_x, axix_x, rgb_regamma,
1440 MAX_HW_POINTS, tf_pts,
1441 (mapUserRamp || ramp->type != GAMMA_RGB_256) &&
1442 ramp->type != GAMMA_CS_TFM_1D);
1443
1444 if (ramp->type == GAMMA_CS_TFM_1D)
1445 apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
1446
1447 ret = true;
1448
1449 kvfree(coeff);
1450 coeff_alloc_fail:
1451 kvfree(axix_x);
1452 axix_x_alloc_fail:
1453 kvfree(rgb_regamma);
1454 rgb_regamma_alloc_fail:
1455 kvfree(rgb_user);
1456 rgb_user_alloc_fail:
1457 return ret;
1458 }
1459
calculate_user_regamma_coeff(struct dc_transfer_func * output_tf,const struct regamma_lut * regamma)1460 bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf,
1461 const struct regamma_lut *regamma)
1462 {
1463 struct gamma_coefficients coeff;
1464 const struct hw_x_point *coord_x = coordinates_x;
1465 uint32_t i = 0;
1466
1467 do {
1468 coeff.a0[i] = dc_fixpt_from_fraction(
1469 regamma->coeff.A0[i], 10000000);
1470 coeff.a1[i] = dc_fixpt_from_fraction(
1471 regamma->coeff.A1[i], 1000);
1472 coeff.a2[i] = dc_fixpt_from_fraction(
1473 regamma->coeff.A2[i], 1000);
1474 coeff.a3[i] = dc_fixpt_from_fraction(
1475 regamma->coeff.A3[i], 1000);
1476 coeff.user_gamma[i] = dc_fixpt_from_fraction(
1477 regamma->coeff.gamma[i], 1000);
1478
1479 ++i;
1480 } while (i != 3);
1481
1482 i = 0;
1483 /* fixed_pt library has problems handling too small values */
1484 while (i != 32) {
1485 output_tf->tf_pts.red[i] = dc_fixpt_zero;
1486 output_tf->tf_pts.green[i] = dc_fixpt_zero;
1487 output_tf->tf_pts.blue[i] = dc_fixpt_zero;
1488 ++coord_x;
1489 ++i;
1490 }
1491 while (i != MAX_HW_POINTS + 1) {
1492 output_tf->tf_pts.red[i] = translate_from_linear_space_ex(
1493 coord_x->x, &coeff, 0);
1494 output_tf->tf_pts.green[i] = translate_from_linear_space_ex(
1495 coord_x->x, &coeff, 1);
1496 output_tf->tf_pts.blue[i] = translate_from_linear_space_ex(
1497 coord_x->x, &coeff, 2);
1498 ++coord_x;
1499 ++i;
1500 }
1501
1502 // this function just clamps output to 0-1
1503 build_new_custom_resulted_curve(MAX_HW_POINTS, &output_tf->tf_pts);
1504 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1505
1506 return true;
1507 }
1508
calculate_user_regamma_ramp(struct dc_transfer_func * output_tf,const struct regamma_lut * regamma)1509 bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf,
1510 const struct regamma_lut *regamma)
1511 {
1512 struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
1513 struct dividers dividers;
1514
1515 struct pwl_float_data *rgb_user = NULL;
1516 struct pwl_float_data_ex *rgb_regamma = NULL;
1517 bool ret = false;
1518
1519 if (regamma == NULL)
1520 return false;
1521
1522 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1523
1524 rgb_user = kcalloc(GAMMA_RGB_256_ENTRIES + _EXTRA_POINTS,
1525 sizeof(*rgb_user),
1526 GFP_KERNEL);
1527 if (!rgb_user)
1528 goto rgb_user_alloc_fail;
1529
1530 rgb_regamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1531 sizeof(*rgb_regamma),
1532 GFP_KERNEL);
1533 if (!rgb_regamma)
1534 goto rgb_regamma_alloc_fail;
1535
1536 dividers.divider1 = dc_fixpt_from_fraction(3, 2);
1537 dividers.divider2 = dc_fixpt_from_int(2);
1538 dividers.divider3 = dc_fixpt_from_fraction(5, 2);
1539
1540 scale_user_regamma_ramp(rgb_user, ®amma->ramp, dividers);
1541
1542 if (regamma->flags.bits.applyDegamma == 1) {
1543 apply_degamma_for_user_regamma(rgb_regamma, MAX_HW_POINTS);
1544 copy_rgb_regamma_to_coordinates_x(coordinates_x,
1545 MAX_HW_POINTS, rgb_regamma);
1546 }
1547
1548 interpolate_user_regamma(MAX_HW_POINTS, rgb_user,
1549 regamma->flags.bits.applyDegamma, tf_pts);
1550
1551 // no custom HDR curves!
1552 tf_pts->end_exponent = 0;
1553 tf_pts->x_point_at_y1_red = 1;
1554 tf_pts->x_point_at_y1_green = 1;
1555 tf_pts->x_point_at_y1_blue = 1;
1556
1557 // this function just clamps output to 0-1
1558 build_new_custom_resulted_curve(MAX_HW_POINTS, tf_pts);
1559
1560 ret = true;
1561
1562 kfree(rgb_regamma);
1563 rgb_regamma_alloc_fail:
1564 kfree(rgb_user);
1565 rgb_user_alloc_fail:
1566 return ret;
1567 }
1568
mod_color_calculate_degamma_params(struct dc_transfer_func * input_tf,const struct dc_gamma * ramp,bool mapUserRamp)1569 bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
1570 const struct dc_gamma *ramp, bool mapUserRamp)
1571 {
1572 struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts;
1573 struct dividers dividers;
1574
1575 struct pwl_float_data *rgb_user = NULL;
1576 struct pwl_float_data_ex *curve = NULL;
1577 struct gamma_pixel *axix_x = NULL;
1578 struct pixel_gamma_point *coeff = NULL;
1579 enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1580 bool ret = false;
1581
1582 if (input_tf->type == TF_TYPE_BYPASS)
1583 return false;
1584
1585 /* we can use hardcoded curve for plain SRGB TF */
1586 if (input_tf->type == TF_TYPE_PREDEFINED &&
1587 input_tf->tf == TRANSFER_FUNCTION_SRGB &&
1588 (!mapUserRamp && ramp->type == GAMMA_RGB_256))
1589 return true;
1590
1591 input_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1592
1593 rgb_user = kcalloc(ramp->num_entries + _EXTRA_POINTS,
1594 sizeof(*rgb_user),
1595 GFP_KERNEL);
1596 if (!rgb_user)
1597 goto rgb_user_alloc_fail;
1598 curve = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*curve),
1599 GFP_KERNEL);
1600 if (!curve)
1601 goto curve_alloc_fail;
1602 axix_x = kcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axix_x),
1603 GFP_KERNEL);
1604 if (!axix_x)
1605 goto axix_x_alloc_fail;
1606 coeff = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff),
1607 GFP_KERNEL);
1608 if (!coeff)
1609 goto coeff_alloc_fail;
1610
1611 dividers.divider1 = dc_fixpt_from_fraction(3, 2);
1612 dividers.divider2 = dc_fixpt_from_int(2);
1613 dividers.divider3 = dc_fixpt_from_fraction(5, 2);
1614
1615 tf = input_tf->tf;
1616
1617 build_evenly_distributed_points(
1618 axix_x,
1619 ramp->num_entries,
1620 dividers);
1621
1622 if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
1623 scale_gamma(rgb_user, ramp, dividers);
1624 else if (ramp->type == GAMMA_RGB_FLOAT_1024)
1625 scale_gamma_dx(rgb_user, ramp, dividers);
1626
1627 if (tf == TRANSFER_FUNCTION_PQ)
1628 build_de_pq(curve,
1629 MAX_HW_POINTS,
1630 coordinates_x);
1631 else
1632 build_degamma(curve,
1633 MAX_HW_POINTS,
1634 coordinates_x,
1635 tf == TRANSFER_FUNCTION_SRGB ? true:false);
1636
1637 tf_pts->end_exponent = 0;
1638 tf_pts->x_point_at_y1_red = 1;
1639 tf_pts->x_point_at_y1_green = 1;
1640 tf_pts->x_point_at_y1_blue = 1;
1641
1642 map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1643 coordinates_x, axix_x, curve,
1644 MAX_HW_POINTS, tf_pts,
1645 mapUserRamp && ramp->type != GAMMA_CUSTOM);
1646 if (ramp->type == GAMMA_CUSTOM)
1647 apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
1648
1649 ret = true;
1650
1651 kvfree(coeff);
1652 coeff_alloc_fail:
1653 kvfree(axix_x);
1654 axix_x_alloc_fail:
1655 kvfree(curve);
1656 curve_alloc_fail:
1657 kvfree(rgb_user);
1658 rgb_user_alloc_fail:
1659
1660 return ret;
1661
1662 }
1663
1664
mod_color_calculate_curve(enum dc_transfer_func_predefined trans,struct dc_transfer_func_distributed_points * points)1665 bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans,
1666 struct dc_transfer_func_distributed_points *points)
1667 {
1668 uint32_t i;
1669 bool ret = false;
1670 struct pwl_float_data_ex *rgb_regamma = NULL;
1671
1672 if (trans == TRANSFER_FUNCTION_UNITY ||
1673 trans == TRANSFER_FUNCTION_LINEAR) {
1674 points->end_exponent = 0;
1675 points->x_point_at_y1_red = 1;
1676 points->x_point_at_y1_green = 1;
1677 points->x_point_at_y1_blue = 1;
1678
1679 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1680 points->red[i] = coordinates_x[i].x;
1681 points->green[i] = coordinates_x[i].x;
1682 points->blue[i] = coordinates_x[i].x;
1683 }
1684 ret = true;
1685 } else if (trans == TRANSFER_FUNCTION_PQ) {
1686 rgb_regamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1687 sizeof(*rgb_regamma),
1688 GFP_KERNEL);
1689 if (!rgb_regamma)
1690 goto rgb_regamma_alloc_fail;
1691 points->end_exponent = 7;
1692 points->x_point_at_y1_red = 125;
1693 points->x_point_at_y1_green = 125;
1694 points->x_point_at_y1_blue = 125;
1695
1696
1697 build_pq(rgb_regamma,
1698 MAX_HW_POINTS,
1699 coordinates_x,
1700 80);
1701 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1702 points->red[i] = rgb_regamma[i].r;
1703 points->green[i] = rgb_regamma[i].g;
1704 points->blue[i] = rgb_regamma[i].b;
1705 }
1706 ret = true;
1707
1708 kvfree(rgb_regamma);
1709 } else if (trans == TRANSFER_FUNCTION_SRGB ||
1710 trans == TRANSFER_FUNCTION_BT709) {
1711 rgb_regamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1712 sizeof(*rgb_regamma),
1713 GFP_KERNEL);
1714 if (!rgb_regamma)
1715 goto rgb_regamma_alloc_fail;
1716 points->end_exponent = 0;
1717 points->x_point_at_y1_red = 1;
1718 points->x_point_at_y1_green = 1;
1719 points->x_point_at_y1_blue = 1;
1720
1721 build_regamma(rgb_regamma,
1722 MAX_HW_POINTS,
1723 coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false);
1724 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1725 points->red[i] = rgb_regamma[i].r;
1726 points->green[i] = rgb_regamma[i].g;
1727 points->blue[i] = rgb_regamma[i].b;
1728 }
1729 ret = true;
1730
1731 kvfree(rgb_regamma);
1732 } else if (trans == TRANSFER_FUNCTION_HLG ||
1733 trans == TRANSFER_FUNCTION_HLG12) {
1734 rgb_regamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1735 sizeof(*rgb_regamma),
1736 GFP_KERNEL);
1737 if (!rgb_regamma)
1738 goto rgb_regamma_alloc_fail;
1739
1740 build_hlg_regamma(rgb_regamma,
1741 MAX_HW_POINTS,
1742 coordinates_x,
1743 trans == TRANSFER_FUNCTION_HLG12 ? true:false);
1744 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1745 points->red[i] = rgb_regamma[i].r;
1746 points->green[i] = rgb_regamma[i].g;
1747 points->blue[i] = rgb_regamma[i].b;
1748 }
1749 ret = true;
1750 kvfree(rgb_regamma);
1751 }
1752 rgb_regamma_alloc_fail:
1753 return ret;
1754 }
1755
1756
mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,struct dc_transfer_func_distributed_points * points)1757 bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
1758 struct dc_transfer_func_distributed_points *points)
1759 {
1760 uint32_t i;
1761 bool ret = false;
1762 struct pwl_float_data_ex *rgb_degamma = NULL;
1763
1764 if (trans == TRANSFER_FUNCTION_UNITY ||
1765 trans == TRANSFER_FUNCTION_LINEAR) {
1766
1767 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1768 points->red[i] = coordinates_x[i].x;
1769 points->green[i] = coordinates_x[i].x;
1770 points->blue[i] = coordinates_x[i].x;
1771 }
1772 ret = true;
1773 } else if (trans == TRANSFER_FUNCTION_PQ) {
1774 rgb_degamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1775 sizeof(*rgb_degamma),
1776 GFP_KERNEL);
1777 if (!rgb_degamma)
1778 goto rgb_degamma_alloc_fail;
1779
1780
1781 build_de_pq(rgb_degamma,
1782 MAX_HW_POINTS,
1783 coordinates_x);
1784 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1785 points->red[i] = rgb_degamma[i].r;
1786 points->green[i] = rgb_degamma[i].g;
1787 points->blue[i] = rgb_degamma[i].b;
1788 }
1789 ret = true;
1790
1791 kvfree(rgb_degamma);
1792 } else if (trans == TRANSFER_FUNCTION_SRGB ||
1793 trans == TRANSFER_FUNCTION_BT709) {
1794 rgb_degamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1795 sizeof(*rgb_degamma),
1796 GFP_KERNEL);
1797 if (!rgb_degamma)
1798 goto rgb_degamma_alloc_fail;
1799
1800 build_degamma(rgb_degamma,
1801 MAX_HW_POINTS,
1802 coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false);
1803 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1804 points->red[i] = rgb_degamma[i].r;
1805 points->green[i] = rgb_degamma[i].g;
1806 points->blue[i] = rgb_degamma[i].b;
1807 }
1808 ret = true;
1809
1810 kvfree(rgb_degamma);
1811 } else if (trans == TRANSFER_FUNCTION_HLG ||
1812 trans == TRANSFER_FUNCTION_HLG12) {
1813 rgb_degamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1814 sizeof(*rgb_degamma),
1815 GFP_KERNEL);
1816 if (!rgb_degamma)
1817 goto rgb_degamma_alloc_fail;
1818
1819 build_hlg_degamma(rgb_degamma,
1820 MAX_HW_POINTS,
1821 coordinates_x,
1822 trans == TRANSFER_FUNCTION_HLG12 ? true:false);
1823 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1824 points->red[i] = rgb_degamma[i].r;
1825 points->green[i] = rgb_degamma[i].g;
1826 points->blue[i] = rgb_degamma[i].b;
1827 }
1828 ret = true;
1829 kvfree(rgb_degamma);
1830 }
1831 points->end_exponent = 0;
1832 points->x_point_at_y1_red = 1;
1833 points->x_point_at_y1_green = 1;
1834 points->x_point_at_y1_blue = 1;
1835
1836 rgb_degamma_alloc_fail:
1837 return ret;
1838 }
1839
1840
1841