Line data Source code
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 : #include "dc.h"
26 : #include "reg_helper.h"
27 : #include "dcn10_dpp.h"
28 :
29 : #include "dcn10_cm_common.h"
30 : #include "custom_float.h"
31 :
32 : #define REG(reg) reg
33 :
34 : #define CTX \
35 : ctx
36 :
37 : #undef FN
38 : #define FN(reg_name, field_name) \
39 : reg->shifts.field_name, reg->masks.field_name
40 :
41 0 : void cm_helper_program_color_matrices(
42 : struct dc_context *ctx,
43 : const uint16_t *regval,
44 : const struct color_matrices_reg *reg)
45 : {
46 : uint32_t cur_csc_reg;
47 0 : unsigned int i = 0;
48 :
49 0 : for (cur_csc_reg = reg->csc_c11_c12;
50 0 : cur_csc_reg <= reg->csc_c33_c34;
51 0 : cur_csc_reg++) {
52 :
53 0 : const uint16_t *regval0 = &(regval[2 * i]);
54 0 : const uint16_t *regval1 = &(regval[(2 * i) + 1]);
55 :
56 0 : REG_SET_2(cur_csc_reg, 0,
57 : csc_c11, *regval0,
58 : csc_c12, *regval1);
59 :
60 0 : i++;
61 : }
62 :
63 0 : }
64 :
65 0 : void cm_helper_program_xfer_func(
66 : struct dc_context *ctx,
67 : const struct pwl_params *params,
68 : const struct xfer_func_reg *reg)
69 : {
70 : uint32_t reg_region_cur;
71 0 : unsigned int i = 0;
72 :
73 0 : REG_SET_2(reg->start_cntl_b, 0,
74 : exp_region_start, params->corner_points[0].blue.custom_float_x,
75 : exp_resion_start_segment, 0);
76 0 : REG_SET_2(reg->start_cntl_g, 0,
77 : exp_region_start, params->corner_points[0].green.custom_float_x,
78 : exp_resion_start_segment, 0);
79 0 : REG_SET_2(reg->start_cntl_r, 0,
80 : exp_region_start, params->corner_points[0].red.custom_float_x,
81 : exp_resion_start_segment, 0);
82 :
83 0 : REG_SET(reg->start_slope_cntl_b, 0,
84 : field_region_linear_slope, params->corner_points[0].blue.custom_float_slope);
85 0 : REG_SET(reg->start_slope_cntl_g, 0,
86 : field_region_linear_slope, params->corner_points[0].green.custom_float_slope);
87 0 : REG_SET(reg->start_slope_cntl_r, 0,
88 : field_region_linear_slope, params->corner_points[0].red.custom_float_slope);
89 :
90 0 : REG_SET(reg->start_end_cntl1_b, 0,
91 : field_region_end, params->corner_points[1].blue.custom_float_x);
92 0 : REG_SET_2(reg->start_end_cntl2_b, 0,
93 : field_region_end_slope, params->corner_points[1].blue.custom_float_slope,
94 : field_region_end_base, params->corner_points[1].blue.custom_float_y);
95 :
96 0 : REG_SET(reg->start_end_cntl1_g, 0,
97 : field_region_end, params->corner_points[1].green.custom_float_x);
98 0 : REG_SET_2(reg->start_end_cntl2_g, 0,
99 : field_region_end_slope, params->corner_points[1].green.custom_float_slope,
100 : field_region_end_base, params->corner_points[1].green.custom_float_y);
101 :
102 0 : REG_SET(reg->start_end_cntl1_r, 0,
103 : field_region_end, params->corner_points[1].red.custom_float_x);
104 0 : REG_SET_2(reg->start_end_cntl2_r, 0,
105 : field_region_end_slope, params->corner_points[1].red.custom_float_slope,
106 : field_region_end_base, params->corner_points[1].red.custom_float_y);
107 :
108 0 : for (reg_region_cur = reg->region_start;
109 0 : reg_region_cur <= reg->region_end;
110 0 : reg_region_cur++) {
111 :
112 0 : const struct gamma_curve *curve0 = &(params->arr_curve_points[2 * i]);
113 0 : const struct gamma_curve *curve1 = &(params->arr_curve_points[(2 * i) + 1]);
114 :
115 0 : REG_SET_4(reg_region_cur, 0,
116 : exp_region0_lut_offset, curve0->offset,
117 : exp_region0_num_segments, curve0->segments_num,
118 : exp_region1_lut_offset, curve1->offset,
119 : exp_region1_num_segments, curve1->segments_num);
120 :
121 0 : i++;
122 : }
123 :
124 0 : }
125 :
126 :
127 :
128 0 : bool cm_helper_convert_to_custom_float(
129 : struct pwl_result_data *rgb_resulted,
130 : struct curve_points3 *corner_points,
131 : uint32_t hw_points_num,
132 : bool fixpoint)
133 : {
134 : struct custom_float_format fmt;
135 :
136 0 : struct pwl_result_data *rgb = rgb_resulted;
137 :
138 0 : uint32_t i = 0;
139 :
140 0 : fmt.exponenta_bits = 6;
141 0 : fmt.mantissa_bits = 12;
142 0 : fmt.sign = false;
143 :
144 : /* corner_points[0] - beginning base, slope offset for R,G,B
145 : * corner_points[1] - end base, slope offset for R,G,B
146 : */
147 0 : if (!convert_to_custom_float_format(corner_points[0].red.x, &fmt,
148 : &corner_points[0].red.custom_float_x)) {
149 0 : BREAK_TO_DEBUGGER();
150 0 : return false;
151 : }
152 0 : if (!convert_to_custom_float_format(corner_points[0].green.x, &fmt,
153 : &corner_points[0].green.custom_float_x)) {
154 0 : BREAK_TO_DEBUGGER();
155 0 : return false;
156 : }
157 0 : if (!convert_to_custom_float_format(corner_points[0].blue.x, &fmt,
158 : &corner_points[0].blue.custom_float_x)) {
159 0 : BREAK_TO_DEBUGGER();
160 0 : return false;
161 : }
162 :
163 0 : if (!convert_to_custom_float_format(corner_points[0].red.offset, &fmt,
164 : &corner_points[0].red.custom_float_offset)) {
165 0 : BREAK_TO_DEBUGGER();
166 0 : return false;
167 : }
168 0 : if (!convert_to_custom_float_format(corner_points[0].green.offset, &fmt,
169 : &corner_points[0].green.custom_float_offset)) {
170 0 : BREAK_TO_DEBUGGER();
171 0 : return false;
172 : }
173 0 : if (!convert_to_custom_float_format(corner_points[0].blue.offset, &fmt,
174 : &corner_points[0].blue.custom_float_offset)) {
175 0 : BREAK_TO_DEBUGGER();
176 0 : return false;
177 : }
178 :
179 0 : if (!convert_to_custom_float_format(corner_points[0].red.slope, &fmt,
180 : &corner_points[0].red.custom_float_slope)) {
181 0 : BREAK_TO_DEBUGGER();
182 0 : return false;
183 : }
184 0 : if (!convert_to_custom_float_format(corner_points[0].green.slope, &fmt,
185 : &corner_points[0].green.custom_float_slope)) {
186 0 : BREAK_TO_DEBUGGER();
187 0 : return false;
188 : }
189 0 : if (!convert_to_custom_float_format(corner_points[0].blue.slope, &fmt,
190 : &corner_points[0].blue.custom_float_slope)) {
191 0 : BREAK_TO_DEBUGGER();
192 0 : return false;
193 : }
194 :
195 0 : fmt.mantissa_bits = 10;
196 0 : fmt.sign = false;
197 :
198 0 : if (!convert_to_custom_float_format(corner_points[1].red.x, &fmt,
199 : &corner_points[1].red.custom_float_x)) {
200 0 : BREAK_TO_DEBUGGER();
201 0 : return false;
202 : }
203 0 : if (!convert_to_custom_float_format(corner_points[1].green.x, &fmt,
204 : &corner_points[1].green.custom_float_x)) {
205 0 : BREAK_TO_DEBUGGER();
206 0 : return false;
207 : }
208 0 : if (!convert_to_custom_float_format(corner_points[1].blue.x, &fmt,
209 : &corner_points[1].blue.custom_float_x)) {
210 0 : BREAK_TO_DEBUGGER();
211 0 : return false;
212 : }
213 :
214 0 : if (fixpoint == true) {
215 0 : corner_points[1].red.custom_float_y =
216 0 : dc_fixpt_clamp_u0d14(corner_points[1].red.y);
217 0 : corner_points[1].green.custom_float_y =
218 0 : dc_fixpt_clamp_u0d14(corner_points[1].green.y);
219 0 : corner_points[1].blue.custom_float_y =
220 0 : dc_fixpt_clamp_u0d14(corner_points[1].blue.y);
221 : } else {
222 0 : if (!convert_to_custom_float_format(corner_points[1].red.y,
223 : &fmt, &corner_points[1].red.custom_float_y)) {
224 0 : BREAK_TO_DEBUGGER();
225 0 : return false;
226 : }
227 0 : if (!convert_to_custom_float_format(corner_points[1].green.y,
228 : &fmt, &corner_points[1].green.custom_float_y)) {
229 0 : BREAK_TO_DEBUGGER();
230 0 : return false;
231 : }
232 0 : if (!convert_to_custom_float_format(corner_points[1].blue.y,
233 : &fmt, &corner_points[1].blue.custom_float_y)) {
234 0 : BREAK_TO_DEBUGGER();
235 0 : return false;
236 : }
237 : }
238 :
239 0 : if (!convert_to_custom_float_format(corner_points[1].red.slope, &fmt,
240 : &corner_points[1].red.custom_float_slope)) {
241 0 : BREAK_TO_DEBUGGER();
242 0 : return false;
243 : }
244 0 : if (!convert_to_custom_float_format(corner_points[1].green.slope, &fmt,
245 : &corner_points[1].green.custom_float_slope)) {
246 0 : BREAK_TO_DEBUGGER();
247 0 : return false;
248 : }
249 0 : if (!convert_to_custom_float_format(corner_points[1].blue.slope, &fmt,
250 : &corner_points[1].blue.custom_float_slope)) {
251 0 : BREAK_TO_DEBUGGER();
252 0 : return false;
253 : }
254 :
255 0 : if (hw_points_num == 0 || rgb_resulted == NULL || fixpoint == true)
256 : return true;
257 :
258 0 : fmt.mantissa_bits = 12;
259 0 : fmt.sign = true;
260 :
261 0 : while (i != hw_points_num) {
262 0 : if (!convert_to_custom_float_format(rgb->red, &fmt,
263 : &rgb->red_reg)) {
264 0 : BREAK_TO_DEBUGGER();
265 0 : return false;
266 : }
267 :
268 0 : if (!convert_to_custom_float_format(rgb->green, &fmt,
269 : &rgb->green_reg)) {
270 0 : BREAK_TO_DEBUGGER();
271 0 : return false;
272 : }
273 :
274 0 : if (!convert_to_custom_float_format(rgb->blue, &fmt,
275 : &rgb->blue_reg)) {
276 0 : BREAK_TO_DEBUGGER();
277 0 : return false;
278 : }
279 :
280 0 : if (!convert_to_custom_float_format(rgb->delta_red, &fmt,
281 : &rgb->delta_red_reg)) {
282 0 : BREAK_TO_DEBUGGER();
283 0 : return false;
284 : }
285 :
286 0 : if (!convert_to_custom_float_format(rgb->delta_green, &fmt,
287 : &rgb->delta_green_reg)) {
288 0 : BREAK_TO_DEBUGGER();
289 0 : return false;
290 : }
291 :
292 0 : if (!convert_to_custom_float_format(rgb->delta_blue, &fmt,
293 : &rgb->delta_blue_reg)) {
294 0 : BREAK_TO_DEBUGGER();
295 0 : return false;
296 : }
297 :
298 0 : ++rgb;
299 0 : ++i;
300 : }
301 :
302 : return true;
303 : }
304 :
305 : /* driver uses 32 regions or less, but DCN HW has 34, extra 2 are set to 0 */
306 : #define MAX_REGIONS_NUMBER 34
307 : #define MAX_LOW_POINT 25
308 : #define NUMBER_REGIONS 32
309 : #define NUMBER_SW_SEGMENTS 16
310 :
311 0 : bool cm_helper_translate_curve_to_hw_format(
312 : const struct dc_transfer_func *output_tf,
313 : struct pwl_params *lut_params, bool fixpoint)
314 : {
315 : struct curve_points3 *corner_points;
316 : struct pwl_result_data *rgb_resulted;
317 : struct pwl_result_data *rgb;
318 : struct pwl_result_data *rgb_plus_1;
319 : struct pwl_result_data *rgb_minus_1;
320 :
321 : int32_t region_start, region_end;
322 : int32_t i;
323 : uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
324 :
325 0 : if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
326 : return false;
327 :
328 0 : corner_points = lut_params->corner_points;
329 0 : rgb_resulted = lut_params->rgb_resulted;
330 0 : hw_points = 0;
331 :
332 0 : memset(lut_params, 0, sizeof(struct pwl_params));
333 0 : memset(seg_distr, 0, sizeof(seg_distr));
334 :
335 0 : if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22) {
336 : /* 32 segments
337 : * segments are from 2^-25 to 2^7
338 : */
339 0 : for (i = 0; i < NUMBER_REGIONS ; i++)
340 0 : seg_distr[i] = 3;
341 :
342 : region_start = -MAX_LOW_POINT;
343 : region_end = NUMBER_REGIONS - MAX_LOW_POINT;
344 : } else {
345 : /* 11 segments
346 : * segment is from 2^-10 to 2^1
347 : * There are less than 256 points, for optimization
348 : */
349 0 : seg_distr[0] = 3;
350 0 : seg_distr[1] = 4;
351 0 : seg_distr[2] = 4;
352 0 : seg_distr[3] = 4;
353 0 : seg_distr[4] = 4;
354 0 : seg_distr[5] = 4;
355 0 : seg_distr[6] = 4;
356 0 : seg_distr[7] = 4;
357 0 : seg_distr[8] = 4;
358 0 : seg_distr[9] = 4;
359 0 : seg_distr[10] = 1;
360 :
361 0 : region_start = -10;
362 0 : region_end = 1;
363 : }
364 :
365 0 : for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
366 0 : seg_distr[i] = -1;
367 :
368 0 : for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
369 0 : if (seg_distr[k] != -1)
370 0 : hw_points += (1 << seg_distr[k]);
371 : }
372 :
373 : j = 0;
374 0 : for (k = 0; k < (region_end - region_start); k++) {
375 0 : increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
376 0 : start_index = (region_start + k + MAX_LOW_POINT) *
377 : NUMBER_SW_SEGMENTS;
378 0 : for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
379 0 : i += increment) {
380 0 : if (j == hw_points - 1)
381 : break;
382 0 : rgb_resulted[j].red = output_tf->tf_pts.red[i];
383 0 : rgb_resulted[j].green = output_tf->tf_pts.green[i];
384 0 : rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
385 0 : j++;
386 : }
387 : }
388 :
389 : /* last point */
390 0 : start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
391 0 : rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
392 0 : rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
393 0 : rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
394 :
395 0 : rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red;
396 0 : rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
397 0 : rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue;
398 :
399 : // All 3 color channels have same x
400 0 : corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
401 : dc_fixpt_from_int(region_start));
402 0 : corner_points[0].green.x = corner_points[0].red.x;
403 0 : corner_points[0].blue.x = corner_points[0].red.x;
404 :
405 0 : corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
406 : dc_fixpt_from_int(region_end));
407 0 : corner_points[1].green.x = corner_points[1].red.x;
408 0 : corner_points[1].blue.x = corner_points[1].red.x;
409 :
410 0 : corner_points[0].red.y = rgb_resulted[0].red;
411 0 : corner_points[0].green.y = rgb_resulted[0].green;
412 0 : corner_points[0].blue.y = rgb_resulted[0].blue;
413 :
414 0 : corner_points[0].red.slope = dc_fixpt_div(corner_points[0].red.y,
415 : corner_points[0].red.x);
416 0 : corner_points[0].green.slope = dc_fixpt_div(corner_points[0].green.y,
417 : corner_points[0].green.x);
418 0 : corner_points[0].blue.slope = dc_fixpt_div(corner_points[0].blue.y,
419 : corner_points[0].blue.x);
420 :
421 : /* see comment above, m_arrPoints[1].y should be the Y value for the
422 : * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
423 : */
424 0 : corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
425 0 : corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
426 0 : corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
427 0 : corner_points[1].red.slope = dc_fixpt_zero;
428 0 : corner_points[1].green.slope = dc_fixpt_zero;
429 0 : corner_points[1].blue.slope = dc_fixpt_zero;
430 :
431 0 : if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
432 : /* for PQ, we want to have a straight line from last HW X point,
433 : * and the slope to be such that we hit 1.0 at 10000 nits.
434 : */
435 0 : const struct fixed31_32 end_value =
436 : dc_fixpt_from_int(125);
437 :
438 0 : corner_points[1].red.slope = dc_fixpt_div(
439 : dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
440 : dc_fixpt_sub(end_value, corner_points[1].red.x));
441 0 : corner_points[1].green.slope = dc_fixpt_div(
442 : dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
443 : dc_fixpt_sub(end_value, corner_points[1].green.x));
444 0 : corner_points[1].blue.slope = dc_fixpt_div(
445 : dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
446 : dc_fixpt_sub(end_value, corner_points[1].blue.x));
447 : }
448 :
449 0 : lut_params->hw_points_num = hw_points;
450 :
451 0 : k = 0;
452 0 : for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
453 0 : if (seg_distr[k] != -1) {
454 0 : lut_params->arr_curve_points[k].segments_num =
455 : seg_distr[k];
456 0 : lut_params->arr_curve_points[i].offset =
457 0 : lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
458 : }
459 0 : k++;
460 : }
461 :
462 0 : if (seg_distr[k] != -1)
463 0 : lut_params->arr_curve_points[k].segments_num = seg_distr[k];
464 :
465 0 : rgb = rgb_resulted;
466 0 : rgb_plus_1 = rgb_resulted + 1;
467 0 : rgb_minus_1 = rgb;
468 :
469 0 : i = 1;
470 0 : while (i != hw_points + 1) {
471 :
472 0 : if (i >= hw_points - 1) {
473 0 : if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
474 0 : rgb_plus_1->red = dc_fixpt_add(rgb->red, rgb_minus_1->delta_red);
475 0 : if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
476 0 : rgb_plus_1->green = dc_fixpt_add(rgb->green, rgb_minus_1->delta_green);
477 0 : if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
478 0 : rgb_plus_1->blue = dc_fixpt_add(rgb->blue, rgb_minus_1->delta_blue);
479 : }
480 :
481 0 : rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red);
482 0 : rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
483 0 : rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue);
484 :
485 0 : if (fixpoint == true) {
486 0 : rgb->delta_red_reg = dc_fixpt_clamp_u0d10(rgb->delta_red);
487 0 : rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
488 0 : rgb->delta_blue_reg = dc_fixpt_clamp_u0d10(rgb->delta_blue);
489 0 : rgb->red_reg = dc_fixpt_clamp_u0d14(rgb->red);
490 0 : rgb->green_reg = dc_fixpt_clamp_u0d14(rgb->green);
491 0 : rgb->blue_reg = dc_fixpt_clamp_u0d14(rgb->blue);
492 : }
493 :
494 0 : ++rgb_plus_1;
495 0 : rgb_minus_1 = rgb;
496 0 : ++rgb;
497 0 : ++i;
498 : }
499 0 : cm_helper_convert_to_custom_float(rgb_resulted,
500 : lut_params->corner_points,
501 : hw_points, fixpoint);
502 :
503 0 : return true;
504 : }
505 :
506 : #define NUM_DEGAMMA_REGIONS 12
507 :
508 :
509 0 : bool cm_helper_translate_curve_to_degamma_hw_format(
510 : const struct dc_transfer_func *output_tf,
511 : struct pwl_params *lut_params)
512 : {
513 : struct curve_points3 *corner_points;
514 : struct pwl_result_data *rgb_resulted;
515 : struct pwl_result_data *rgb;
516 : struct pwl_result_data *rgb_plus_1;
517 :
518 : int32_t region_start, region_end;
519 : int32_t i;
520 : uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
521 :
522 0 : if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
523 : return false;
524 :
525 0 : corner_points = lut_params->corner_points;
526 0 : rgb_resulted = lut_params->rgb_resulted;
527 0 : hw_points = 0;
528 :
529 0 : memset(lut_params, 0, sizeof(struct pwl_params));
530 0 : memset(seg_distr, 0, sizeof(seg_distr));
531 :
532 0 : region_start = -NUM_DEGAMMA_REGIONS;
533 0 : region_end = 0;
534 :
535 :
536 0 : for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
537 0 : seg_distr[i] = -1;
538 : /* 12 segments
539 : * segments are from 2^-12 to 0
540 : */
541 0 : for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++)
542 0 : seg_distr[i] = 4;
543 :
544 0 : for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
545 0 : if (seg_distr[k] != -1)
546 0 : hw_points += (1 << seg_distr[k]);
547 : }
548 :
549 : j = 0;
550 0 : for (k = 0; k < (region_end - region_start); k++) {
551 0 : increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
552 0 : start_index = (region_start + k + MAX_LOW_POINT) *
553 : NUMBER_SW_SEGMENTS;
554 0 : for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
555 0 : i += increment) {
556 0 : if (j == hw_points - 1)
557 : break;
558 0 : rgb_resulted[j].red = output_tf->tf_pts.red[i];
559 0 : rgb_resulted[j].green = output_tf->tf_pts.green[i];
560 0 : rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
561 0 : j++;
562 : }
563 : }
564 :
565 : /* last point */
566 0 : start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
567 0 : rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
568 0 : rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
569 0 : rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
570 :
571 0 : rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red;
572 0 : rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
573 0 : rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue;
574 :
575 0 : corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
576 : dc_fixpt_from_int(region_start));
577 0 : corner_points[0].green.x = corner_points[0].red.x;
578 0 : corner_points[0].blue.x = corner_points[0].red.x;
579 0 : corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
580 : dc_fixpt_from_int(region_end));
581 0 : corner_points[1].green.x = corner_points[1].red.x;
582 0 : corner_points[1].blue.x = corner_points[1].red.x;
583 :
584 0 : corner_points[0].red.y = rgb_resulted[0].red;
585 0 : corner_points[0].green.y = rgb_resulted[0].green;
586 0 : corner_points[0].blue.y = rgb_resulted[0].blue;
587 :
588 : /* see comment above, m_arrPoints[1].y should be the Y value for the
589 : * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
590 : */
591 0 : corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
592 0 : corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
593 0 : corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
594 0 : corner_points[1].red.slope = dc_fixpt_zero;
595 0 : corner_points[1].green.slope = dc_fixpt_zero;
596 0 : corner_points[1].blue.slope = dc_fixpt_zero;
597 :
598 0 : if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
599 : /* for PQ, we want to have a straight line from last HW X point,
600 : * and the slope to be such that we hit 1.0 at 10000 nits.
601 : */
602 0 : const struct fixed31_32 end_value =
603 : dc_fixpt_from_int(125);
604 :
605 0 : corner_points[1].red.slope = dc_fixpt_div(
606 : dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
607 : dc_fixpt_sub(end_value, corner_points[1].red.x));
608 0 : corner_points[1].green.slope = dc_fixpt_div(
609 : dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
610 : dc_fixpt_sub(end_value, corner_points[1].green.x));
611 0 : corner_points[1].blue.slope = dc_fixpt_div(
612 : dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
613 : dc_fixpt_sub(end_value, corner_points[1].blue.x));
614 : }
615 :
616 0 : lut_params->hw_points_num = hw_points;
617 :
618 0 : k = 0;
619 0 : for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
620 0 : if (seg_distr[k] != -1) {
621 0 : lut_params->arr_curve_points[k].segments_num =
622 : seg_distr[k];
623 0 : lut_params->arr_curve_points[i].offset =
624 0 : lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
625 : }
626 0 : k++;
627 : }
628 :
629 0 : if (seg_distr[k] != -1)
630 0 : lut_params->arr_curve_points[k].segments_num = seg_distr[k];
631 :
632 0 : rgb = rgb_resulted;
633 0 : rgb_plus_1 = rgb_resulted + 1;
634 :
635 0 : i = 1;
636 0 : while (i != hw_points + 1) {
637 0 : rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red);
638 0 : rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
639 0 : rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue);
640 :
641 0 : ++rgb_plus_1;
642 0 : ++rgb;
643 0 : ++i;
644 : }
645 0 : cm_helper_convert_to_custom_float(rgb_resulted,
646 : lut_params->corner_points,
647 : hw_points, false);
648 :
649 0 : return true;
650 : }
|