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