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