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 /* When calculating LUT values the first region and at least one subsequent 31 * region are calculated with full precision. These defines are a demarcation 32 * of where the second region starts and ends. 33 * These are hardcoded values to avoid recalculating them in loops. 34 */ 35 #define PRECISE_LUT_REGION_START 224 36 #define PRECISE_LUT_REGION_END 239 37 38 static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2]; 39 40 // Hardcoded table that depends on setup_x_points_distribution and sdr_level=80 41 // If x points are changed, then PQ Y points will be misaligned and a new 42 // table would need to be generated. Or use old method that calls compute_pq. 43 // The last point is above PQ formula range (0-125 in normalized FP16) 44 // The value for the last point (128) is such that interpolation from 45 // 120 to 128 will give 1.0 for X = 125.0 46 // first couple points are 0 - HW LUT is mirrored around zero, so making first 47 // segment 0 to 0 will effectively clip it, and these are very low PQ codes 48 // min nonzero value below (216825) is a little under 12-bit PQ code 1. 49 static const unsigned long long pq_divider = 1000000000; 50 static const unsigned long long pq_numerator[MAX_HW_POINTS + 1] = { 51 0, 0, 0, 0, 216825, 222815, 52 228691, 234460, 240128, 245702, 251187, 256587, 53 261908, 267152, 272324, 277427, 282465, 292353, 54 302011, 311456, 320704, 329768, 338661, 347394, 55 355975, 364415, 372721, 380900, 388959, 396903, 56 404739, 412471, 420104, 435089, 449727, 464042, 57 478060, 491800, 505281, 518520, 531529, 544324, 58 556916, 569316, 581533, 593576, 605454, 617175, 59 628745, 651459, 673643, 695337, 716578, 737395, 60 757817, 777869, 797572, 816947, 836012, 854782, 61 873274, 891500, 909474, 927207, 944709, 979061, 62 1012601, 1045391, 1077485, 1108931, 1139770, 1170042, 63 1199778, 1229011, 1257767, 1286071, 1313948, 1341416, 64 1368497, 1395207, 1421563, 1473272, 1523733, 1573041, 65 1621279, 1668520, 1714828, 1760262, 1804874, 1848710, 66 1891814, 1934223, 1975973, 2017096, 2057622, 2097578, 67 2136989, 2214269, 2289629, 2363216, 2435157, 2505564, 68 2574539, 2642169, 2708536, 2773711, 2837760, 2900742, 69 2962712, 3023719, 3083810, 3143025, 3201405, 3315797, 70 3427246, 3535974, 3642181, 3746038, 3847700, 3947305, 71 4044975, 4140823, 4234949, 4327445, 4418394, 4507872, 72 4595951, 4682694, 4768161, 4935487, 5098326, 5257022, 73 5411878, 5563161, 5711107, 5855928, 5997812, 6136929, 74 6273436, 6407471, 6539163, 6668629, 6795976, 6921304, 75 7044703, 7286050, 7520623, 7748950, 7971492, 8188655, 76 8400800, 8608247, 8811286, 9010175, 9205149, 9396421, 77 9584186, 9768620, 9949889, 10128140, 10303513, 10646126, 78 10978648, 11301874, 11616501, 11923142, 12222340, 12514578, 79 12800290, 13079866, 13353659, 13621988, 13885144, 14143394, 80 14396982, 14646132, 14891052, 15368951, 15832050, 16281537, 81 16718448, 17143696, 17558086, 17962337, 18357092, 18742927, 82 19120364, 19489877, 19851894, 20206810, 20554983, 20896745, 83 21232399, 21886492, 22519276, 23132491, 23727656, 24306104, 84 24869013, 25417430, 25952292, 26474438, 26984626, 27483542, 85 27971811, 28450000, 28918632, 29378184, 29829095, 30706591, 86 31554022, 32373894, 33168387, 33939412, 34688657, 35417620, 87 36127636, 36819903, 37495502, 38155408, 38800507, 39431607, 88 40049446, 40654702, 41247996, 42400951, 43512407, 44585892, 89 45624474, 46630834, 47607339, 48556082, 49478931, 50377558, 90 51253467, 52108015, 52942436, 53757848, 54555277, 55335659, 91 56099856, 57582802, 59009766, 60385607, 61714540, 63000246, 92 64245964, 65454559, 66628579, 67770304, 68881781, 69964856, 93 71021203, 72052340, 73059655, 74044414, 75007782, 76874537, 94 78667536, 80393312, 82057522, 83665098, 85220372, 86727167, 95 88188883, 89608552, 90988895, 92332363, 93641173, 94917336, 96 96162685, 97378894, 98567496, 100867409, 103072439, 105191162, 97 107230989, 109198368, 111098951, 112937723, 114719105, 116447036, 98 118125045, 119756307, 121343688, 122889787, 124396968, 125867388, 99 127303021, 130077030, 132731849, 135278464, 137726346, 140083726, 100 142357803, 144554913, 146680670, 148740067, 150737572, 152677197, 101 154562560, 156396938, 158183306, 159924378, 161622632, 164899602, 102 168030318, 171028513, 173906008, 176673051, 179338593, 181910502, 103 184395731, 186800463, 189130216, 191389941, 193584098, 195716719, 104 197791463, 199811660, 201780351, 205574133, 209192504, 212652233, 105 215967720, 219151432, 222214238, 225165676, 228014163, 230767172, 106 233431363, 236012706, 238516569, 240947800, 243310793, 245609544, 107 247847696, 252155270, 256257056, 260173059, 263920427, 267513978, 108 270966613, 274289634, 277493001, 280585542, 283575118, 286468763, 109 289272796, 291992916, 294634284, 297201585, 299699091, 304500003, 110 309064541, 313416043, 317574484, 321557096, 325378855, 329052864, 111 332590655, 336002433, 339297275, 342483294, 345567766, 348557252, 112 351457680, 354274432, 357012407, 362269536, 367260561, 372012143, 113 376547060, 380884936, 385042798, 389035522, 392876185, 396576344, 114 400146265, 403595112, 406931099, 410161619, 413293351, 416332348, 115 419284117, 424945627, 430313203, 435416697, 440281572, 444929733, 116 449380160, 453649415, 457752035, 461700854, 465507260, 469181407, 117 472732388, 476168376, 479496748, 482724188, 485856764, 491858986, 118 497542280, 502939446, 508078420, 512983199, 517674549, 522170569, 119 526487126, 530638214, 534636233, 538492233, 542216094, 545816693, 120 549302035, 552679362, 555955249, 562226134, 568156709, 573782374, 121 579133244, 584235153, 589110430, 593778512, 598256421, 602559154, 122 606699989, 610690741, 614541971, 618263157, 621862836, 625348729, 123 628727839, 635190643, 641295921, 647081261, 652578597, 657815287, 124 662814957, 667598146, 672182825, 676584810, 680818092, 684895111, 125 688826974, 692623643, 696294085, 699846401, 703287935, 709864782, 126 716071394, 721947076, 727525176, 732834238, 737898880, 742740485, 127 747377745, 751827095, 756103063, 760218552, 764185078, 768012958, 128 771711474, 775289005, 778753144, 785368225, 791604988, 797503949, 129 803099452, 808420859, 813493471, 818339244, 822977353, 827424644, 130 831695997, 835804619, 839762285, 843579541, 847265867, 850829815, 131 854279128, 860861356, 867061719, 872921445, 878475444, 883753534, 132 888781386, 893581259, 898172578, 902572393, 906795754, 910856010, 133 914765057, 918533538, 922171018, 925686119, 929086644, 935571664, 134 941675560, 947439782, 952899395, 958084324, 963020312, 967729662, 135 972231821, 976543852, 980680801, 984656009, 988481353, 992167459, 136 995723865, 999159168, 1002565681}; 137 138 // these are helpers for calculations to reduce stack usage 139 // do not depend on these being preserved across calls 140 141 /* Helper to optimize gamma calculation, only use in translate_from_linear, in 142 * particular the dc_fixpt_pow function which is very expensive 143 * The idea is that our regions for X points are exponential and currently they all use 144 * the same number of points (NUM_PTS_IN_REGION) and in each region every point 145 * is exactly 2x the one at the same index in the previous region. In other words 146 * X[i] = 2 * X[i-NUM_PTS_IN_REGION] for i>=16 147 * The other fact is that (2x)^gamma = 2^gamma * x^gamma 148 * So we compute and save x^gamma for the first 16 regions, and for every next region 149 * just multiply with 2^gamma which can be computed once, and save the result so we 150 * recursively compute all the values. 151 */ 152 153 /* 154 * Regamma coefficients are used for both regamma and degamma. Degamma 155 * coefficients are calculated in our formula using the regamma coefficients. 156 */ 157 /*sRGB 709 2.2 2.4 P3*/ 158 static const int32_t numerator01[] = { 31308, 180000, 0, 0, 0}; 159 static const int32_t numerator02[] = { 12920, 4500, 0, 0, 0}; 160 static const int32_t numerator03[] = { 55, 99, 0, 0, 0}; 161 static const int32_t numerator04[] = { 55, 99, 0, 0, 0}; 162 static const int32_t numerator05[] = { 2400, 2222, 2200, 2400, 2600}; 163 164 /* one-time setup of X points */ 165 void setup_x_points_distribution(void) 166 { 167 struct fixed31_32 region_size = dc_fixpt_from_int(128); 168 int32_t segment; 169 uint32_t seg_offset; 170 uint32_t index; 171 struct fixed31_32 increment; 172 173 coordinates_x[MAX_HW_POINTS].x = region_size; 174 coordinates_x[MAX_HW_POINTS + 1].x = region_size; 175 176 for (segment = 6; segment > (6 - NUM_REGIONS); segment--) { 177 region_size = dc_fixpt_div_int(region_size, 2); 178 increment = dc_fixpt_div_int(region_size, 179 NUM_PTS_IN_REGION); 180 seg_offset = (segment + (NUM_REGIONS - 7)) * NUM_PTS_IN_REGION; 181 coordinates_x[seg_offset].x = region_size; 182 183 for (index = seg_offset + 1; 184 index < seg_offset + NUM_PTS_IN_REGION; 185 index++) { 186 coordinates_x[index].x = dc_fixpt_add 187 (coordinates_x[index-1].x, increment); 188 } 189 } 190 } 191 192 void log_x_points_distribution(struct dal_logger *logger) 193 { 194 int i = 0; 195 196 if (logger != NULL) { 197 LOG_GAMMA_WRITE("Log X Distribution\n"); 198 199 for (i = 0; i < MAX_HW_POINTS; i++) 200 LOG_GAMMA_WRITE("%llu\n", coordinates_x[i].x.value); 201 } 202 } 203 204 static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) 205 { 206 /* consts for PQ gamma formula. */ 207 const struct fixed31_32 m1 = 208 dc_fixpt_from_fraction(159301758, 1000000000); 209 const struct fixed31_32 m2 = 210 dc_fixpt_from_fraction(7884375, 100000); 211 const struct fixed31_32 c1 = 212 dc_fixpt_from_fraction(8359375, 10000000); 213 const struct fixed31_32 c2 = 214 dc_fixpt_from_fraction(188515625, 10000000); 215 const struct fixed31_32 c3 = 216 dc_fixpt_from_fraction(186875, 10000); 217 218 struct fixed31_32 l_pow_m1; 219 struct fixed31_32 base; 220 221 if (dc_fixpt_lt(in_x, dc_fixpt_zero)) 222 in_x = dc_fixpt_zero; 223 224 l_pow_m1 = dc_fixpt_pow(in_x, m1); 225 base = dc_fixpt_div( 226 dc_fixpt_add(c1, 227 (dc_fixpt_mul(c2, l_pow_m1))), 228 dc_fixpt_add(dc_fixpt_one, 229 (dc_fixpt_mul(c3, l_pow_m1)))); 230 *out_y = dc_fixpt_pow(base, m2); 231 } 232 233 static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) 234 { 235 /* consts for dePQ gamma formula. */ 236 const struct fixed31_32 m1 = 237 dc_fixpt_from_fraction(159301758, 1000000000); 238 const struct fixed31_32 m2 = 239 dc_fixpt_from_fraction(7884375, 100000); 240 const struct fixed31_32 c1 = 241 dc_fixpt_from_fraction(8359375, 10000000); 242 const struct fixed31_32 c2 = 243 dc_fixpt_from_fraction(188515625, 10000000); 244 const struct fixed31_32 c3 = 245 dc_fixpt_from_fraction(186875, 10000); 246 247 struct fixed31_32 l_pow_m1; 248 struct fixed31_32 base, div; 249 struct fixed31_32 base2; 250 251 252 if (dc_fixpt_lt(in_x, dc_fixpt_zero)) 253 in_x = dc_fixpt_zero; 254 255 l_pow_m1 = dc_fixpt_pow(in_x, 256 dc_fixpt_div(dc_fixpt_one, m2)); 257 base = dc_fixpt_sub(l_pow_m1, c1); 258 259 div = dc_fixpt_sub(c2, dc_fixpt_mul(c3, l_pow_m1)); 260 261 base2 = dc_fixpt_div(base, div); 262 // avoid complex numbers 263 if (dc_fixpt_lt(base2, dc_fixpt_zero)) 264 base2 = dc_fixpt_sub(dc_fixpt_zero, base2); 265 266 267 *out_y = dc_fixpt_pow(base2, dc_fixpt_div(dc_fixpt_one, m1)); 268 269 } 270 271 272 /* de gamma, non-linear to linear */ 273 static void compute_hlg_eotf(struct fixed31_32 in_x, 274 struct fixed31_32 *out_y, 275 uint32_t sdr_white_level, uint32_t max_luminance_nits) 276 { 277 struct fixed31_32 a; 278 struct fixed31_32 b; 279 struct fixed31_32 c; 280 struct fixed31_32 threshold; 281 struct fixed31_32 x; 282 283 struct fixed31_32 scaling_factor = 284 dc_fixpt_from_fraction(max_luminance_nits, sdr_white_level); 285 a = dc_fixpt_from_fraction(17883277, 100000000); 286 b = dc_fixpt_from_fraction(28466892, 100000000); 287 c = dc_fixpt_from_fraction(55991073, 100000000); 288 threshold = dc_fixpt_from_fraction(1, 2); 289 290 if (dc_fixpt_lt(in_x, threshold)) { 291 x = dc_fixpt_mul(in_x, in_x); 292 x = dc_fixpt_div_int(x, 3); 293 } else { 294 x = dc_fixpt_sub(in_x, c); 295 x = dc_fixpt_div(x, a); 296 x = dc_fixpt_exp(x); 297 x = dc_fixpt_add(x, b); 298 x = dc_fixpt_div_int(x, 12); 299 } 300 *out_y = dc_fixpt_mul(x, scaling_factor); 301 302 } 303 304 /* re gamma, linear to non-linear */ 305 static void compute_hlg_oetf(struct fixed31_32 in_x, struct fixed31_32 *out_y, 306 uint32_t sdr_white_level, uint32_t max_luminance_nits) 307 { 308 struct fixed31_32 a; 309 struct fixed31_32 b; 310 struct fixed31_32 c; 311 struct fixed31_32 threshold; 312 struct fixed31_32 x; 313 314 struct fixed31_32 scaling_factor = 315 dc_fixpt_from_fraction(sdr_white_level, max_luminance_nits); 316 a = dc_fixpt_from_fraction(17883277, 100000000); 317 b = dc_fixpt_from_fraction(28466892, 100000000); 318 c = dc_fixpt_from_fraction(55991073, 100000000); 319 threshold = dc_fixpt_from_fraction(1, 12); 320 x = dc_fixpt_mul(in_x, scaling_factor); 321 322 323 if (dc_fixpt_lt(x, threshold)) { 324 x = dc_fixpt_mul(x, dc_fixpt_from_fraction(3, 1)); 325 *out_y = dc_fixpt_pow(x, dc_fixpt_half); 326 } else { 327 x = dc_fixpt_mul(x, dc_fixpt_from_fraction(12, 1)); 328 x = dc_fixpt_sub(x, b); 329 x = dc_fixpt_log(x); 330 x = dc_fixpt_mul(a, x); 331 *out_y = dc_fixpt_add(x, c); 332 } 333 } 334 335 336 /* one-time pre-compute PQ values - only for sdr_white_level 80 */ 337 void precompute_pq(void) 338 { 339 int i; 340 struct fixed31_32 *pq_table = mod_color_get_table(type_pq_table); 341 342 for (i = 0; i <= MAX_HW_POINTS; i++) 343 pq_table[i] = dc_fixpt_from_fraction(pq_numerator[i], pq_divider); 344 345 /* below is old method that uses run-time calculation in fixed pt space */ 346 /* pow function has problems with arguments too small */ 347 /* 348 struct fixed31_32 x; 349 const struct hw_x_point *coord_x = coordinates_x + 32; 350 struct fixed31_32 scaling_factor = 351 dc_fixpt_from_fraction(80, 10000); 352 353 for (i = 0; i < 32; i++) 354 pq_table[i] = dc_fixpt_zero; 355 356 for (i = 32; i <= MAX_HW_POINTS; i++) { 357 x = dc_fixpt_mul(coord_x->x, scaling_factor); 358 compute_pq(x, &pq_table[i]); 359 ++coord_x; 360 } 361 */ 362 } 363 364 /* one-time pre-compute dePQ values - only for max pixel value 125 FP16 */ 365 void precompute_de_pq(void) 366 { 367 int i; 368 struct fixed31_32 y; 369 uint32_t begin_index, end_index; 370 371 struct fixed31_32 scaling_factor = dc_fixpt_from_int(125); 372 struct fixed31_32 *de_pq_table = mod_color_get_table(type_de_pq_table); 373 /* X points is 2^-25 to 2^7 374 * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions 375 */ 376 begin_index = 13 * NUM_PTS_IN_REGION; 377 end_index = begin_index + 12 * NUM_PTS_IN_REGION; 378 379 for (i = 0; i <= begin_index; i++) 380 de_pq_table[i] = dc_fixpt_zero; 381 382 for (; i <= end_index; i++) { 383 compute_de_pq(coordinates_x[i].x, &y); 384 de_pq_table[i] = dc_fixpt_mul(y, scaling_factor); 385 } 386 387 for (; i <= MAX_HW_POINTS; i++) 388 de_pq_table[i] = de_pq_table[i-1]; 389 } 390 struct dividers { 391 struct fixed31_32 divider1; 392 struct fixed31_32 divider2; 393 struct fixed31_32 divider3; 394 }; 395 396 397 static bool build_coefficients(struct gamma_coefficients *coefficients, 398 enum dc_transfer_func_predefined type) 399 { 400 401 uint32_t i = 0; 402 uint32_t index = 0; 403 bool ret = true; 404 405 if (type == TRANSFER_FUNCTION_SRGB) 406 index = 0; 407 else if (type == TRANSFER_FUNCTION_BT709) 408 index = 1; 409 else if (type == TRANSFER_FUNCTION_GAMMA22) 410 index = 2; 411 else if (type == TRANSFER_FUNCTION_GAMMA24) 412 index = 3; 413 else if (type == TRANSFER_FUNCTION_GAMMA26) 414 index = 4; 415 else { 416 ret = false; 417 goto release; 418 } 419 420 do { 421 coefficients->a0[i] = dc_fixpt_from_fraction( 422 numerator01[index], 10000000); 423 coefficients->a1[i] = dc_fixpt_from_fraction( 424 numerator02[index], 1000); 425 coefficients->a2[i] = dc_fixpt_from_fraction( 426 numerator03[index], 1000); 427 coefficients->a3[i] = dc_fixpt_from_fraction( 428 numerator04[index], 1000); 429 coefficients->user_gamma[i] = dc_fixpt_from_fraction( 430 numerator05[index], 1000); 431 432 ++i; 433 } while (i != ARRAY_SIZE(coefficients->a0)); 434 release: 435 return ret; 436 } 437 438 static struct fixed31_32 translate_from_linear_space( 439 struct translate_from_linear_space_args *args) 440 { 441 const struct fixed31_32 one = dc_fixpt_from_int(1); 442 443 struct fixed31_32 scratch_1, scratch_2; 444 struct calculate_buffer *cal_buffer = args->cal_buffer; 445 446 if (dc_fixpt_le(one, args->arg)) 447 return one; 448 449 if (dc_fixpt_le(args->arg, dc_fixpt_neg(args->a0))) { 450 scratch_1 = dc_fixpt_add(one, args->a3); 451 scratch_2 = dc_fixpt_pow( 452 dc_fixpt_neg(args->arg), 453 dc_fixpt_recip(args->gamma)); 454 scratch_1 = dc_fixpt_mul(scratch_1, scratch_2); 455 scratch_1 = dc_fixpt_sub(args->a2, scratch_1); 456 457 return scratch_1; 458 } else if (dc_fixpt_le(args->a0, args->arg)) { 459 if (cal_buffer->buffer_index == 0) { 460 cal_buffer->gamma_of_2 = dc_fixpt_pow(dc_fixpt_from_int(2), 461 dc_fixpt_recip(args->gamma)); 462 } 463 scratch_1 = dc_fixpt_add(one, args->a3); 464 /* In the first region (first 16 points) and in the 465 * region delimited by START/END we calculate with 466 * full precision to avoid error accumulation. 467 */ 468 if ((cal_buffer->buffer_index >= PRECISE_LUT_REGION_START && 469 cal_buffer->buffer_index <= PRECISE_LUT_REGION_END) || 470 (cal_buffer->buffer_index < 16)) 471 scratch_2 = dc_fixpt_pow(args->arg, 472 dc_fixpt_recip(args->gamma)); 473 else 474 scratch_2 = dc_fixpt_mul(cal_buffer->gamma_of_2, 475 cal_buffer->buffer[cal_buffer->buffer_index%16]); 476 477 if (cal_buffer->buffer_index != -1) { 478 cal_buffer->buffer[cal_buffer->buffer_index%16] = scratch_2; 479 cal_buffer->buffer_index++; 480 } 481 482 scratch_1 = dc_fixpt_mul(scratch_1, scratch_2); 483 scratch_1 = dc_fixpt_sub(scratch_1, args->a2); 484 485 return scratch_1; 486 } else 487 return dc_fixpt_mul(args->arg, args->a1); 488 } 489 490 491 static struct fixed31_32 translate_from_linear_space_long( 492 struct translate_from_linear_space_args *args) 493 { 494 const struct fixed31_32 one = dc_fixpt_from_int(1); 495 496 if (dc_fixpt_lt(one, args->arg)) 497 return one; 498 499 if (dc_fixpt_le(args->arg, dc_fixpt_neg(args->a0))) 500 return dc_fixpt_sub( 501 args->a2, 502 dc_fixpt_mul( 503 dc_fixpt_add( 504 one, 505 args->a3), 506 dc_fixpt_pow( 507 dc_fixpt_neg(args->arg), 508 dc_fixpt_recip(args->gamma)))); 509 else if (dc_fixpt_le(args->a0, args->arg)) 510 return dc_fixpt_sub( 511 dc_fixpt_mul( 512 dc_fixpt_add( 513 one, 514 args->a3), 515 dc_fixpt_pow( 516 args->arg, 517 dc_fixpt_recip(args->gamma))), 518 args->a2); 519 else 520 return dc_fixpt_mul(args->arg, args->a1); 521 } 522 523 static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg, bool use_eetf, struct calculate_buffer *cal_buffer) 524 { 525 struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10); 526 struct translate_from_linear_space_args scratch_gamma_args; 527 528 scratch_gamma_args.arg = arg; 529 scratch_gamma_args.a0 = dc_fixpt_zero; 530 scratch_gamma_args.a1 = dc_fixpt_zero; 531 scratch_gamma_args.a2 = dc_fixpt_zero; 532 scratch_gamma_args.a3 = dc_fixpt_zero; 533 scratch_gamma_args.cal_buffer = cal_buffer; 534 scratch_gamma_args.gamma = gamma; 535 536 if (use_eetf) 537 return translate_from_linear_space_long(&scratch_gamma_args); 538 539 return translate_from_linear_space(&scratch_gamma_args); 540 } 541 542 543 static struct fixed31_32 translate_to_linear_space( 544 struct fixed31_32 arg, 545 struct fixed31_32 a0, 546 struct fixed31_32 a1, 547 struct fixed31_32 a2, 548 struct fixed31_32 a3, 549 struct fixed31_32 gamma) 550 { 551 struct fixed31_32 linear; 552 553 a0 = dc_fixpt_mul(a0, a1); 554 if (dc_fixpt_le(arg, dc_fixpt_neg(a0))) 555 556 linear = dc_fixpt_neg( 557 dc_fixpt_pow( 558 dc_fixpt_div( 559 dc_fixpt_sub(a2, arg), 560 dc_fixpt_add( 561 dc_fixpt_one, a3)), gamma)); 562 563 else if (dc_fixpt_le(dc_fixpt_neg(a0), arg) && 564 dc_fixpt_le(arg, a0)) 565 linear = dc_fixpt_div(arg, a1); 566 else 567 linear = dc_fixpt_pow( 568 dc_fixpt_div( 569 dc_fixpt_add(a2, arg), 570 dc_fixpt_add( 571 dc_fixpt_one, a3)), gamma); 572 573 return linear; 574 } 575 576 static struct fixed31_32 translate_from_linear_space_ex( 577 struct fixed31_32 arg, 578 struct gamma_coefficients *coeff, 579 uint32_t color_index, 580 struct calculate_buffer *cal_buffer) 581 { 582 struct translate_from_linear_space_args scratch_gamma_args; 583 584 scratch_gamma_args.arg = arg; 585 scratch_gamma_args.a0 = coeff->a0[color_index]; 586 scratch_gamma_args.a1 = coeff->a1[color_index]; 587 scratch_gamma_args.a2 = coeff->a2[color_index]; 588 scratch_gamma_args.a3 = coeff->a3[color_index]; 589 scratch_gamma_args.gamma = coeff->user_gamma[color_index]; 590 scratch_gamma_args.cal_buffer = cal_buffer; 591 592 return translate_from_linear_space(&scratch_gamma_args); 593 } 594 595 596 static inline struct fixed31_32 translate_to_linear_space_ex( 597 struct fixed31_32 arg, 598 struct gamma_coefficients *coeff, 599 uint32_t color_index) 600 { 601 return translate_to_linear_space( 602 arg, 603 coeff->a0[color_index], 604 coeff->a1[color_index], 605 coeff->a2[color_index], 606 coeff->a3[color_index], 607 coeff->user_gamma[color_index]); 608 } 609 610 611 static bool find_software_points( 612 const struct dc_gamma *ramp, 613 const struct gamma_pixel *axis_x, 614 struct fixed31_32 hw_point, 615 enum channel_name channel, 616 uint32_t *index_to_start, 617 uint32_t *index_left, 618 uint32_t *index_right, 619 enum hw_point_position *pos) 620 { 621 const uint32_t max_number = ramp->num_entries + 3; 622 623 struct fixed31_32 left, right; 624 625 uint32_t i = *index_to_start; 626 627 while (i < max_number) { 628 if (channel == CHANNEL_NAME_RED) { 629 left = axis_x[i].r; 630 631 if (i < max_number - 1) 632 right = axis_x[i + 1].r; 633 else 634 right = axis_x[max_number - 1].r; 635 } else if (channel == CHANNEL_NAME_GREEN) { 636 left = axis_x[i].g; 637 638 if (i < max_number - 1) 639 right = axis_x[i + 1].g; 640 else 641 right = axis_x[max_number - 1].g; 642 } else { 643 left = axis_x[i].b; 644 645 if (i < max_number - 1) 646 right = axis_x[i + 1].b; 647 else 648 right = axis_x[max_number - 1].b; 649 } 650 651 if (dc_fixpt_le(left, hw_point) && 652 dc_fixpt_le(hw_point, right)) { 653 *index_to_start = i; 654 *index_left = i; 655 656 if (i < max_number - 1) 657 *index_right = i + 1; 658 else 659 *index_right = max_number - 1; 660 661 *pos = HW_POINT_POSITION_MIDDLE; 662 663 return true; 664 } else if ((i == *index_to_start) && 665 dc_fixpt_le(hw_point, left)) { 666 *index_to_start = i; 667 *index_left = i; 668 *index_right = i; 669 670 *pos = HW_POINT_POSITION_LEFT; 671 672 return true; 673 } else if ((i == max_number - 1) && 674 dc_fixpt_le(right, hw_point)) { 675 *index_to_start = i; 676 *index_left = i; 677 *index_right = i; 678 679 *pos = HW_POINT_POSITION_RIGHT; 680 681 return true; 682 } 683 684 ++i; 685 } 686 687 return false; 688 } 689 690 static bool build_custom_gamma_mapping_coefficients_worker( 691 const struct dc_gamma *ramp, 692 struct pixel_gamma_point *coeff, 693 const struct hw_x_point *coordinates_x, 694 const struct gamma_pixel *axis_x, 695 enum channel_name channel, 696 uint32_t number_of_points) 697 { 698 uint32_t i = 0; 699 700 while (i <= number_of_points) { 701 struct fixed31_32 coord_x; 702 703 uint32_t index_to_start = 0; 704 uint32_t index_left = 0; 705 uint32_t index_right = 0; 706 707 enum hw_point_position hw_pos; 708 709 struct gamma_point *point; 710 711 struct fixed31_32 left_pos; 712 struct fixed31_32 right_pos; 713 714 if (channel == CHANNEL_NAME_RED) 715 coord_x = coordinates_x[i].regamma_y_red; 716 else if (channel == CHANNEL_NAME_GREEN) 717 coord_x = coordinates_x[i].regamma_y_green; 718 else 719 coord_x = coordinates_x[i].regamma_y_blue; 720 721 if (!find_software_points( 722 ramp, axis_x, coord_x, channel, 723 &index_to_start, &index_left, &index_right, &hw_pos)) { 724 BREAK_TO_DEBUGGER(); 725 return false; 726 } 727 728 if (index_left >= ramp->num_entries + 3) { 729 BREAK_TO_DEBUGGER(); 730 return false; 731 } 732 733 if (index_right >= ramp->num_entries + 3) { 734 BREAK_TO_DEBUGGER(); 735 return false; 736 } 737 738 if (channel == CHANNEL_NAME_RED) { 739 point = &coeff[i].r; 740 741 left_pos = axis_x[index_left].r; 742 right_pos = axis_x[index_right].r; 743 } else if (channel == CHANNEL_NAME_GREEN) { 744 point = &coeff[i].g; 745 746 left_pos = axis_x[index_left].g; 747 right_pos = axis_x[index_right].g; 748 } else { 749 point = &coeff[i].b; 750 751 left_pos = axis_x[index_left].b; 752 right_pos = axis_x[index_right].b; 753 } 754 755 if (hw_pos == HW_POINT_POSITION_MIDDLE) 756 point->coeff = dc_fixpt_div( 757 dc_fixpt_sub( 758 coord_x, 759 left_pos), 760 dc_fixpt_sub( 761 right_pos, 762 left_pos)); 763 else if (hw_pos == HW_POINT_POSITION_LEFT) 764 point->coeff = dc_fixpt_zero; 765 else if (hw_pos == HW_POINT_POSITION_RIGHT) 766 point->coeff = dc_fixpt_from_int(2); 767 else { 768 BREAK_TO_DEBUGGER(); 769 return false; 770 } 771 772 point->left_index = index_left; 773 point->right_index = index_right; 774 point->pos = hw_pos; 775 776 ++i; 777 } 778 779 return true; 780 } 781 782 static struct fixed31_32 calculate_mapped_value( 783 struct pwl_float_data *rgb, 784 const struct pixel_gamma_point *coeff, 785 enum channel_name channel, 786 uint32_t max_index) 787 { 788 const struct gamma_point *point; 789 790 struct fixed31_32 result; 791 792 if (channel == CHANNEL_NAME_RED) 793 point = &coeff->r; 794 else if (channel == CHANNEL_NAME_GREEN) 795 point = &coeff->g; 796 else 797 point = &coeff->b; 798 799 if ((point->left_index < 0) || (point->left_index > max_index)) { 800 BREAK_TO_DEBUGGER(); 801 return dc_fixpt_zero; 802 } 803 804 if ((point->right_index < 0) || (point->right_index > max_index)) { 805 BREAK_TO_DEBUGGER(); 806 return dc_fixpt_zero; 807 } 808 809 if (point->pos == HW_POINT_POSITION_MIDDLE) 810 if (channel == CHANNEL_NAME_RED) 811 result = dc_fixpt_add( 812 dc_fixpt_mul( 813 point->coeff, 814 dc_fixpt_sub( 815 rgb[point->right_index].r, 816 rgb[point->left_index].r)), 817 rgb[point->left_index].r); 818 else if (channel == CHANNEL_NAME_GREEN) 819 result = dc_fixpt_add( 820 dc_fixpt_mul( 821 point->coeff, 822 dc_fixpt_sub( 823 rgb[point->right_index].g, 824 rgb[point->left_index].g)), 825 rgb[point->left_index].g); 826 else 827 result = dc_fixpt_add( 828 dc_fixpt_mul( 829 point->coeff, 830 dc_fixpt_sub( 831 rgb[point->right_index].b, 832 rgb[point->left_index].b)), 833 rgb[point->left_index].b); 834 else if (point->pos == HW_POINT_POSITION_LEFT) { 835 BREAK_TO_DEBUGGER(); 836 result = dc_fixpt_zero; 837 } else { 838 result = dc_fixpt_one; 839 } 840 841 return result; 842 } 843 844 static void build_pq(struct pwl_float_data_ex *rgb_regamma, 845 uint32_t hw_points_num, 846 const struct hw_x_point *coordinate_x, 847 uint32_t sdr_white_level) 848 { 849 uint32_t i, start_index; 850 851 struct pwl_float_data_ex *rgb = rgb_regamma; 852 const struct hw_x_point *coord_x = coordinate_x; 853 struct fixed31_32 x; 854 struct fixed31_32 output; 855 struct fixed31_32 scaling_factor = 856 dc_fixpt_from_fraction(sdr_white_level, 10000); 857 struct fixed31_32 *pq_table = mod_color_get_table(type_pq_table); 858 859 if (!mod_color_is_table_init(type_pq_table) && sdr_white_level == 80) { 860 precompute_pq(); 861 mod_color_set_table_init_state(type_pq_table, true); 862 } 863 864 /* TODO: start index is from segment 2^-24, skipping first segment 865 * due to x values too small for power calculations 866 */ 867 start_index = 32; 868 rgb += start_index; 869 coord_x += start_index; 870 871 for (i = start_index; i <= hw_points_num; i++) { 872 /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125. 873 * FP 1.0 = 80nits 874 */ 875 if (sdr_white_level == 80) { 876 output = pq_table[i]; 877 } else { 878 x = dc_fixpt_mul(coord_x->x, scaling_factor); 879 compute_pq(x, &output); 880 } 881 882 /* should really not happen? */ 883 if (dc_fixpt_lt(output, dc_fixpt_zero)) 884 output = dc_fixpt_zero; 885 886 rgb->r = output; 887 rgb->g = output; 888 rgb->b = output; 889 890 ++coord_x; 891 ++rgb; 892 } 893 } 894 895 static void build_de_pq(struct pwl_float_data_ex *de_pq, 896 uint32_t hw_points_num, 897 const struct hw_x_point *coordinate_x) 898 { 899 (void)coordinate_x; 900 uint32_t i; 901 struct fixed31_32 output; 902 struct fixed31_32 *de_pq_table = mod_color_get_table(type_de_pq_table); 903 struct fixed31_32 scaling_factor = dc_fixpt_from_int(125); 904 905 if (!mod_color_is_table_init(type_de_pq_table)) { 906 precompute_de_pq(); 907 mod_color_set_table_init_state(type_de_pq_table, true); 908 } 909 910 911 for (i = 0; i <= hw_points_num; i++) { 912 output = de_pq_table[i]; 913 /* should really not happen? */ 914 if (dc_fixpt_lt(output, dc_fixpt_zero)) 915 output = dc_fixpt_zero; 916 else if (dc_fixpt_lt(scaling_factor, output)) 917 output = scaling_factor; 918 de_pq[i].r = output; 919 de_pq[i].g = output; 920 de_pq[i].b = output; 921 } 922 } 923 924 static bool build_regamma(struct pwl_float_data_ex *rgb_regamma, 925 uint32_t hw_points_num, 926 const struct hw_x_point *coordinate_x, 927 enum dc_transfer_func_predefined type, 928 struct calculate_buffer *cal_buffer) 929 { 930 uint32_t i; 931 bool ret = false; 932 933 struct gamma_coefficients *coeff; 934 struct pwl_float_data_ex *rgb = rgb_regamma; 935 const struct hw_x_point *coord_x = coordinate_x; 936 937 coeff = kvzalloc_obj(*coeff); 938 if (!coeff) 939 goto release; 940 941 if (!build_coefficients(coeff, type)) 942 goto release; 943 944 memset(cal_buffer->buffer, 0, NUM_PTS_IN_REGION * sizeof(struct fixed31_32)); 945 cal_buffer->buffer_index = 0; // see variable definition for more info 946 947 i = 0; 948 while (i <= hw_points_num) { 949 /* TODO use y vs r,g,b */ 950 rgb->r = translate_from_linear_space_ex( 951 coord_x->x, coeff, 0, cal_buffer); 952 rgb->g = rgb->r; 953 rgb->b = rgb->r; 954 ++coord_x; 955 ++rgb; 956 ++i; 957 } 958 cal_buffer->buffer_index = -1; 959 ret = true; 960 release: 961 kvfree(coeff); 962 return ret; 963 } 964 965 static void hermite_spline_eetf(struct fixed31_32 input_x, 966 struct fixed31_32 max_display, 967 struct fixed31_32 min_display, 968 struct fixed31_32 max_content, 969 struct fixed31_32 *out_x) 970 { 971 struct fixed31_32 min_lum_pq; 972 struct fixed31_32 max_lum_pq; 973 struct fixed31_32 max_content_pq; 974 struct fixed31_32 ks; 975 struct fixed31_32 E1; 976 struct fixed31_32 E2; 977 struct fixed31_32 E3; 978 struct fixed31_32 t; 979 struct fixed31_32 t2; 980 struct fixed31_32 t3; 981 struct fixed31_32 two; 982 struct fixed31_32 three; 983 struct fixed31_32 temp1; 984 struct fixed31_32 temp2; 985 struct fixed31_32 a = dc_fixpt_from_fraction(15, 10); 986 struct fixed31_32 b = dc_fixpt_from_fraction(5, 10); 987 struct fixed31_32 epsilon = dc_fixpt_from_fraction(1, 1000000); // dc_fixpt_epsilon is a bit too small 988 989 if (dc_fixpt_eq(max_content, dc_fixpt_zero)) { 990 *out_x = dc_fixpt_zero; 991 return; 992 } 993 994 compute_pq(input_x, &E1); 995 compute_pq(dc_fixpt_div(min_display, max_content), &min_lum_pq); 996 compute_pq(dc_fixpt_div(max_display, max_content), &max_lum_pq); 997 compute_pq(dc_fixpt_one, &max_content_pq); // always 1? DAL2 code is weird 998 a = dc_fixpt_div(dc_fixpt_add(dc_fixpt_one, b), max_content_pq); // (1+b)/maxContent 999 ks = dc_fixpt_sub(dc_fixpt_mul(a, max_lum_pq), b); // a * max_lum_pq - b 1000 1001 if (dc_fixpt_lt(E1, ks)) 1002 E2 = E1; 1003 else if (dc_fixpt_le(ks, E1) && dc_fixpt_le(E1, dc_fixpt_one)) { 1004 if (dc_fixpt_lt(epsilon, dc_fixpt_sub(dc_fixpt_one, ks))) 1005 // t = (E1 - ks) / (1 - ks) 1006 t = dc_fixpt_div(dc_fixpt_sub(E1, ks), 1007 dc_fixpt_sub(dc_fixpt_one, ks)); 1008 else 1009 t = dc_fixpt_zero; 1010 1011 two = dc_fixpt_from_int(2); 1012 three = dc_fixpt_from_int(3); 1013 1014 t2 = dc_fixpt_mul(t, t); 1015 t3 = dc_fixpt_mul(t2, t); 1016 temp1 = dc_fixpt_mul(two, t3); 1017 temp2 = dc_fixpt_mul(three, t2); 1018 1019 // (2t^3 - 3t^2 + 1) * ks 1020 E2 = dc_fixpt_mul(ks, dc_fixpt_add(dc_fixpt_one, 1021 dc_fixpt_sub(temp1, temp2))); 1022 1023 // (-2t^3 + 3t^2) * max_lum_pq 1024 E2 = dc_fixpt_add(E2, dc_fixpt_mul(max_lum_pq, 1025 dc_fixpt_sub(temp2, temp1))); 1026 1027 temp1 = dc_fixpt_mul(two, t2); 1028 temp2 = dc_fixpt_sub(dc_fixpt_one, ks); 1029 1030 // (t^3 - 2t^2 + t) * (1-ks) 1031 E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2, 1032 dc_fixpt_add(t, dc_fixpt_sub(t3, temp1)))); 1033 } else 1034 E2 = dc_fixpt_one; 1035 1036 temp1 = dc_fixpt_sub(dc_fixpt_one, E2); 1037 temp2 = dc_fixpt_mul(temp1, temp1); 1038 temp2 = dc_fixpt_mul(temp2, temp2); 1039 // temp2 = (1-E2)^4 1040 1041 E3 = dc_fixpt_add(E2, dc_fixpt_mul(min_lum_pq, temp2)); 1042 compute_de_pq(E3, out_x); 1043 1044 *out_x = dc_fixpt_div(*out_x, dc_fixpt_div(max_display, max_content)); 1045 } 1046 1047 static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, 1048 uint32_t hw_points_num, 1049 const struct hw_x_point *coordinate_x, 1050 const struct hdr_tm_params *fs_params, 1051 struct calculate_buffer *cal_buffer) 1052 { 1053 uint32_t i; 1054 struct pwl_float_data_ex *rgb = rgb_regamma; 1055 const struct hw_x_point *coord_x = coordinate_x; 1056 const struct hw_x_point *prv_coord_x = coord_x; 1057 struct fixed31_32 scaledX = dc_fixpt_zero; 1058 struct fixed31_32 scaledX1 = dc_fixpt_zero; 1059 struct fixed31_32 max_display; 1060 struct fixed31_32 min_display; 1061 struct fixed31_32 max_content; 1062 struct fixed31_32 clip = dc_fixpt_one; 1063 struct fixed31_32 output = dc_fixpt_zero; 1064 bool use_eetf = false; 1065 bool is_clipped = false; 1066 struct fixed31_32 sdr_white_level; 1067 struct fixed31_32 coordX_diff; 1068 struct fixed31_32 out_dist_max; 1069 struct fixed31_32 bright_norm; 1070 1071 if (fs_params->max_content == 0 || 1072 fs_params->max_display == 0) 1073 return false; 1074 1075 max_display = dc_fixpt_from_int(fs_params->max_display); 1076 min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000); 1077 max_content = dc_fixpt_from_int(fs_params->max_content); 1078 sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level); 1079 1080 if (fs_params->min_display > 1000) // cap at 0.1 at the bottom 1081 min_display = dc_fixpt_from_fraction(1, 10); 1082 if (fs_params->max_display < 100) // cap at 100 at the top 1083 max_display = dc_fixpt_from_int(100); 1084 1085 // only max used, we don't adjust min luminance 1086 if (fs_params->max_content > fs_params->max_display) 1087 use_eetf = true; 1088 else 1089 max_content = max_display; 1090 1091 if (!use_eetf) 1092 cal_buffer->buffer_index = 0; // see var definition for more info 1093 rgb += 32; // first 32 points have problems with fixed point, too small 1094 coord_x += 32; 1095 1096 for (i = 32; i <= hw_points_num; i++) { 1097 if (!is_clipped) { 1098 if (use_eetf) { 1099 /* max content is equal 1 */ 1100 scaledX1 = dc_fixpt_div(coord_x->x, 1101 dc_fixpt_div(max_content, sdr_white_level)); 1102 hermite_spline_eetf(scaledX1, max_display, min_display, 1103 max_content, &scaledX); 1104 } else 1105 scaledX = dc_fixpt_div(coord_x->x, 1106 dc_fixpt_div(max_display, sdr_white_level)); 1107 1108 if (dc_fixpt_lt(scaledX, clip)) { 1109 if (dc_fixpt_lt(scaledX, dc_fixpt_zero)) 1110 output = dc_fixpt_zero; 1111 else 1112 output = calculate_gamma22(scaledX, use_eetf, cal_buffer); 1113 1114 // Ensure output respects reasonable boundaries 1115 output = dc_fixpt_clamp(output, dc_fixpt_zero, dc_fixpt_one); 1116 1117 rgb->r = output; 1118 rgb->g = output; 1119 rgb->b = output; 1120 } else { 1121 /* Here clipping happens for the first time */ 1122 is_clipped = true; 1123 1124 /* The next few lines implement the equation 1125 * output = prev_out + 1126 * (coord_x->x - prev_coord_x->x) * 1127 * (1.0 - prev_out) / 1128 * (maxDisp/sdr_white_level - prevCoordX) 1129 * 1130 * This equation interpolates the first point 1131 * after max_display/80 so that the slope from 1132 * hw_x_before_max and hw_x_after_max is such 1133 * that we hit Y=1.0 at max_display/80. 1134 */ 1135 1136 coordX_diff = dc_fixpt_sub(coord_x->x, prv_coord_x->x); 1137 out_dist_max = dc_fixpt_sub(dc_fixpt_one, output); 1138 bright_norm = dc_fixpt_div(max_display, sdr_white_level); 1139 1140 output = dc_fixpt_add( 1141 output, dc_fixpt_mul( 1142 coordX_diff, dc_fixpt_div( 1143 out_dist_max, 1144 dc_fixpt_sub(bright_norm, prv_coord_x->x) 1145 ) 1146 ) 1147 ); 1148 1149 /* Relaxing the maximum boundary to 1.07 (instead of 1.0) 1150 * because the last point in the curve must be such that 1151 * the maximum display pixel brightness interpolates to 1152 * exactly 1.0. The worst case scenario was calculated 1153 * around 1.057, so the limit of 1.07 leaves some safety 1154 * margin. 1155 */ 1156 output = dc_fixpt_clamp(output, dc_fixpt_zero, 1157 dc_fixpt_from_fraction(107, 100)); 1158 1159 rgb->r = output; 1160 rgb->g = output; 1161 rgb->b = output; 1162 } 1163 } else { 1164 /* Every other clipping after the first 1165 * one is dealt with here 1166 */ 1167 rgb->r = clip; 1168 rgb->g = clip; 1169 rgb->b = clip; 1170 } 1171 1172 prv_coord_x = coord_x; 1173 ++coord_x; 1174 ++rgb; 1175 } 1176 cal_buffer->buffer_index = -1; 1177 1178 return true; 1179 } 1180 1181 static bool build_degamma(struct pwl_float_data_ex *curve, 1182 uint32_t hw_points_num, 1183 const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type) 1184 { 1185 uint32_t i; 1186 struct gamma_coefficients coeff; 1187 uint32_t begin_index, end_index; 1188 bool ret = false; 1189 1190 if (!build_coefficients(&coeff, type)) 1191 goto release; 1192 1193 i = 0; 1194 1195 /* X points is 2^-25 to 2^7 1196 * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions 1197 */ 1198 begin_index = 13 * NUM_PTS_IN_REGION; 1199 end_index = begin_index + 12 * NUM_PTS_IN_REGION; 1200 1201 while (i != begin_index) { 1202 curve[i].r = dc_fixpt_zero; 1203 curve[i].g = dc_fixpt_zero; 1204 curve[i].b = dc_fixpt_zero; 1205 i++; 1206 } 1207 1208 while (i != end_index) { 1209 curve[i].r = translate_to_linear_space_ex( 1210 coordinate_x[i].x, &coeff, 0); 1211 curve[i].g = curve[i].r; 1212 curve[i].b = curve[i].r; 1213 i++; 1214 } 1215 while (i != hw_points_num + 1) { 1216 curve[i].r = dc_fixpt_one; 1217 curve[i].g = dc_fixpt_one; 1218 curve[i].b = dc_fixpt_one; 1219 i++; 1220 } 1221 ret = true; 1222 release: 1223 return ret; 1224 } 1225 1226 1227 1228 1229 1230 static void build_hlg_degamma(struct pwl_float_data_ex *degamma, 1231 uint32_t hw_points_num, 1232 const struct hw_x_point *coordinate_x, 1233 uint32_t sdr_white_level, uint32_t max_luminance_nits) 1234 { 1235 uint32_t i; 1236 1237 struct pwl_float_data_ex *rgb = degamma; 1238 const struct hw_x_point *coord_x = coordinate_x; 1239 1240 i = 0; 1241 // check when i == 434 1242 while (i != hw_points_num + 1) { 1243 compute_hlg_eotf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); 1244 rgb->g = rgb->r; 1245 rgb->b = rgb->r; 1246 ++coord_x; 1247 ++rgb; 1248 ++i; 1249 } 1250 } 1251 1252 1253 static void build_hlg_regamma(struct pwl_float_data_ex *regamma, 1254 uint32_t hw_points_num, 1255 const struct hw_x_point *coordinate_x, 1256 uint32_t sdr_white_level, uint32_t max_luminance_nits) 1257 { 1258 uint32_t i; 1259 1260 struct pwl_float_data_ex *rgb = regamma; 1261 const struct hw_x_point *coord_x = coordinate_x; 1262 1263 i = 0; 1264 1265 // when i == 471 1266 while (i != hw_points_num + 1) { 1267 compute_hlg_oetf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); 1268 rgb->g = rgb->r; 1269 rgb->b = rgb->r; 1270 ++coord_x; 1271 ++rgb; 1272 ++i; 1273 } 1274 } 1275 1276 static void scale_gamma(struct pwl_float_data *pwl_rgb, 1277 const struct dc_gamma *ramp, 1278 struct dividers dividers) 1279 { 1280 const struct fixed31_32 max_driver = dc_fixpt_from_int(0xFFFF); 1281 const struct fixed31_32 max_os = dc_fixpt_from_int(0xFF00); 1282 struct fixed31_32 scaler = max_os; 1283 uint32_t i; 1284 struct pwl_float_data *rgb = pwl_rgb; 1285 struct pwl_float_data *rgb_last = rgb + ramp->num_entries - 1; 1286 1287 i = 0; 1288 1289 do { 1290 if (dc_fixpt_lt(max_os, ramp->entries.red[i]) || 1291 dc_fixpt_lt(max_os, ramp->entries.green[i]) || 1292 dc_fixpt_lt(max_os, ramp->entries.blue[i])) { 1293 scaler = max_driver; 1294 break; 1295 } 1296 ++i; 1297 } while (i != ramp->num_entries); 1298 1299 i = 0; 1300 1301 do { 1302 rgb->r = dc_fixpt_div( 1303 ramp->entries.red[i], scaler); 1304 rgb->g = dc_fixpt_div( 1305 ramp->entries.green[i], scaler); 1306 rgb->b = dc_fixpt_div( 1307 ramp->entries.blue[i], scaler); 1308 1309 ++rgb; 1310 ++i; 1311 } while (i != ramp->num_entries); 1312 1313 rgb->r = dc_fixpt_mul(rgb_last->r, 1314 dividers.divider1); 1315 rgb->g = dc_fixpt_mul(rgb_last->g, 1316 dividers.divider1); 1317 rgb->b = dc_fixpt_mul(rgb_last->b, 1318 dividers.divider1); 1319 1320 ++rgb; 1321 1322 rgb->r = dc_fixpt_mul(rgb_last->r, 1323 dividers.divider2); 1324 rgb->g = dc_fixpt_mul(rgb_last->g, 1325 dividers.divider2); 1326 rgb->b = dc_fixpt_mul(rgb_last->b, 1327 dividers.divider2); 1328 1329 ++rgb; 1330 1331 rgb->r = dc_fixpt_mul(rgb_last->r, 1332 dividers.divider3); 1333 rgb->g = dc_fixpt_mul(rgb_last->g, 1334 dividers.divider3); 1335 rgb->b = dc_fixpt_mul(rgb_last->b, 1336 dividers.divider3); 1337 } 1338 1339 static void scale_gamma_dx(struct pwl_float_data *pwl_rgb, 1340 const struct dc_gamma *ramp, 1341 struct dividers dividers) 1342 { 1343 (void)dividers; 1344 uint32_t i; 1345 struct fixed31_32 min = dc_fixpt_zero; 1346 struct fixed31_32 max = dc_fixpt_one; 1347 1348 struct fixed31_32 delta = dc_fixpt_zero; 1349 struct fixed31_32 offset = dc_fixpt_zero; 1350 1351 for (i = 0 ; i < ramp->num_entries; i++) { 1352 if (dc_fixpt_lt(ramp->entries.red[i], min)) 1353 min = ramp->entries.red[i]; 1354 1355 if (dc_fixpt_lt(ramp->entries.green[i], min)) 1356 min = ramp->entries.green[i]; 1357 1358 if (dc_fixpt_lt(ramp->entries.blue[i], min)) 1359 min = ramp->entries.blue[i]; 1360 1361 if (dc_fixpt_lt(max, ramp->entries.red[i])) 1362 max = ramp->entries.red[i]; 1363 1364 if (dc_fixpt_lt(max, ramp->entries.green[i])) 1365 max = ramp->entries.green[i]; 1366 1367 if (dc_fixpt_lt(max, ramp->entries.blue[i])) 1368 max = ramp->entries.blue[i]; 1369 } 1370 1371 if (dc_fixpt_lt(min, dc_fixpt_zero)) 1372 delta = dc_fixpt_neg(min); 1373 1374 offset = dc_fixpt_add(min, max); 1375 1376 for (i = 0 ; i < ramp->num_entries; i++) { 1377 pwl_rgb[i].r = dc_fixpt_div( 1378 dc_fixpt_add( 1379 ramp->entries.red[i], delta), offset); 1380 pwl_rgb[i].g = dc_fixpt_div( 1381 dc_fixpt_add( 1382 ramp->entries.green[i], delta), offset); 1383 pwl_rgb[i].b = dc_fixpt_div( 1384 dc_fixpt_add( 1385 ramp->entries.blue[i], delta), offset); 1386 1387 } 1388 1389 pwl_rgb[i].r = dc_fixpt_sub(dc_fixpt_mul_int( 1390 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r); 1391 pwl_rgb[i].g = dc_fixpt_sub(dc_fixpt_mul_int( 1392 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g); 1393 pwl_rgb[i].b = dc_fixpt_sub(dc_fixpt_mul_int( 1394 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b); 1395 ++i; 1396 pwl_rgb[i].r = dc_fixpt_sub(dc_fixpt_mul_int( 1397 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r); 1398 pwl_rgb[i].g = dc_fixpt_sub(dc_fixpt_mul_int( 1399 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g); 1400 pwl_rgb[i].b = dc_fixpt_sub(dc_fixpt_mul_int( 1401 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b); 1402 } 1403 1404 /* 1405 * RS3+ color transform DDI - 1D LUT adjustment is composed with regamma here 1406 * Input is evenly distributed in the output color space as specified in 1407 * SetTimings 1408 * 1409 * Interpolation details: 1410 * 1D LUT has 4096 values which give curve correction in 0-1 float range 1411 * for evenly spaced points in 0-1 range. lut1D[index] gives correction 1412 * for index/4095. 1413 * First we find index for which: 1414 * index/4095 < regamma_y < (index+1)/4095 => 1415 * index < 4095*regamma_y < index + 1 1416 * norm_y = 4095*regamma_y, and index is just truncating to nearest integer 1417 * lut1 = lut1D[index], lut2 = lut1D[index+1] 1418 * 1419 * adjustedY is then linearly interpolating regamma Y between lut1 and lut2 1420 * 1421 * Custom degamma on Linux uses the same interpolation math, so is handled here 1422 */ 1423 static void apply_lut_1d( 1424 const struct dc_gamma *ramp, 1425 uint32_t num_hw_points, 1426 struct dc_transfer_func_distributed_points *tf_pts) 1427 { 1428 int i = 0; 1429 int color = 0; 1430 struct fixed31_32 *regamma_y; 1431 struct fixed31_32 norm_y; 1432 struct fixed31_32 lut1; 1433 struct fixed31_32 lut2; 1434 const int max_lut_index = 4095; 1435 const struct fixed31_32 penult_lut_index_f = 1436 dc_fixpt_from_int(max_lut_index-1); 1437 const struct fixed31_32 max_lut_index_f = 1438 dc_fixpt_from_int(max_lut_index); 1439 int32_t index = 0, index_next = 0; 1440 struct fixed31_32 index_f; 1441 struct fixed31_32 delta_lut; 1442 struct fixed31_32 delta_index; 1443 1444 if (ramp->type != GAMMA_CS_TFM_1D && ramp->type != GAMMA_CUSTOM) 1445 return; // this is not expected 1446 1447 for (i = 0; i < num_hw_points; i++) { 1448 for (color = 0; color < 3; color++) { 1449 if (color == 0) 1450 regamma_y = &tf_pts->red[i]; 1451 else if (color == 1) 1452 regamma_y = &tf_pts->green[i]; 1453 else 1454 regamma_y = &tf_pts->blue[i]; 1455 1456 norm_y = dc_fixpt_mul(max_lut_index_f, 1457 *regamma_y); 1458 index = dc_fixpt_floor(norm_y); 1459 index_f = dc_fixpt_from_int(index); 1460 1461 if (index < 0) 1462 continue; 1463 1464 if (index <= max_lut_index) 1465 index_next = (index == max_lut_index) ? index : index+1; 1466 else { 1467 /* Here we are dealing with the last point in the curve, 1468 * which in some cases might exceed the range given by 1469 * max_lut_index. So we interpolate the value using 1470 * max_lut_index and max_lut_index - 1. 1471 */ 1472 index = max_lut_index - 1; 1473 index_next = max_lut_index; 1474 index_f = penult_lut_index_f; 1475 } 1476 1477 if (color == 0) { 1478 lut1 = ramp->entries.red[index]; 1479 lut2 = ramp->entries.red[index_next]; 1480 } else if (color == 1) { 1481 lut1 = ramp->entries.green[index]; 1482 lut2 = ramp->entries.green[index_next]; 1483 } else { 1484 lut1 = ramp->entries.blue[index]; 1485 lut2 = ramp->entries.blue[index_next]; 1486 } 1487 1488 // we have everything now, so interpolate 1489 delta_lut = dc_fixpt_sub(lut2, lut1); 1490 delta_index = dc_fixpt_sub(norm_y, index_f); 1491 1492 *regamma_y = dc_fixpt_add(lut1, 1493 dc_fixpt_mul(delta_index, delta_lut)); 1494 } 1495 } 1496 } 1497 1498 static void build_evenly_distributed_points( 1499 struct gamma_pixel *points, 1500 uint32_t numberof_points, 1501 struct dividers dividers) 1502 { 1503 struct gamma_pixel *p = points; 1504 struct gamma_pixel *p_last; 1505 1506 uint32_t i = 0; 1507 1508 // This function should not gets called with 0 as a parameter 1509 ASSERT(numberof_points > 0); 1510 p_last = p + numberof_points - 1; 1511 1512 do { 1513 struct fixed31_32 value = dc_fixpt_from_fraction(i, 1514 numberof_points - 1); 1515 1516 p->r = value; 1517 p->g = value; 1518 p->b = value; 1519 1520 ++p; 1521 ++i; 1522 } while (i < numberof_points); 1523 1524 p->r = dc_fixpt_div(p_last->r, dividers.divider1); 1525 p->g = dc_fixpt_div(p_last->g, dividers.divider1); 1526 p->b = dc_fixpt_div(p_last->b, dividers.divider1); 1527 1528 ++p; 1529 1530 p->r = dc_fixpt_div(p_last->r, dividers.divider2); 1531 p->g = dc_fixpt_div(p_last->g, dividers.divider2); 1532 p->b = dc_fixpt_div(p_last->b, dividers.divider2); 1533 1534 ++p; 1535 1536 p->r = dc_fixpt_div(p_last->r, dividers.divider3); 1537 p->g = dc_fixpt_div(p_last->g, dividers.divider3); 1538 p->b = dc_fixpt_div(p_last->b, dividers.divider3); 1539 } 1540 1541 static inline void copy_rgb_regamma_to_coordinates_x( 1542 struct hw_x_point *coordinates_x, 1543 uint32_t hw_points_num, 1544 const struct pwl_float_data_ex *rgb_ex) 1545 { 1546 struct hw_x_point *coords = coordinates_x; 1547 uint32_t i = 0; 1548 const struct pwl_float_data_ex *rgb_regamma = rgb_ex; 1549 1550 while (i <= hw_points_num + 1) { 1551 coords->regamma_y_red = rgb_regamma->r; 1552 coords->regamma_y_green = rgb_regamma->g; 1553 coords->regamma_y_blue = rgb_regamma->b; 1554 1555 ++coords; 1556 ++rgb_regamma; 1557 ++i; 1558 } 1559 } 1560 1561 static bool calculate_interpolated_hardware_curve( 1562 const struct dc_gamma *ramp, 1563 struct pixel_gamma_point *coeff128, 1564 struct pwl_float_data *rgb_user, 1565 const struct hw_x_point *coordinates_x, 1566 const struct gamma_pixel *axis_x, 1567 uint32_t number_of_points, 1568 struct dc_transfer_func_distributed_points *tf_pts) 1569 { 1570 1571 const struct pixel_gamma_point *coeff = coeff128; 1572 uint32_t max_entries = 3 - 1; 1573 1574 uint32_t i = 0; 1575 1576 for (i = 0; i < 3; i++) { 1577 if (!build_custom_gamma_mapping_coefficients_worker( 1578 ramp, coeff128, coordinates_x, axis_x, i, 1579 number_of_points)) 1580 return false; 1581 } 1582 1583 i = 0; 1584 max_entries += ramp->num_entries; 1585 1586 /* TODO: float point case */ 1587 1588 while (i <= number_of_points) { 1589 tf_pts->red[i] = calculate_mapped_value( 1590 rgb_user, coeff, CHANNEL_NAME_RED, max_entries); 1591 tf_pts->green[i] = calculate_mapped_value( 1592 rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries); 1593 tf_pts->blue[i] = calculate_mapped_value( 1594 rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries); 1595 1596 ++coeff; 1597 ++i; 1598 } 1599 1600 return true; 1601 } 1602 1603 static void build_new_custom_resulted_curve( 1604 uint32_t hw_points_num, 1605 struct dc_transfer_func_distributed_points *tf_pts) 1606 { 1607 uint32_t i = 0; 1608 1609 while (i != hw_points_num + 1) { 1610 tf_pts->red[i] = dc_fixpt_clamp( 1611 tf_pts->red[i], dc_fixpt_zero, 1612 dc_fixpt_one); 1613 tf_pts->green[i] = dc_fixpt_clamp( 1614 tf_pts->green[i], dc_fixpt_zero, 1615 dc_fixpt_one); 1616 tf_pts->blue[i] = dc_fixpt_clamp( 1617 tf_pts->blue[i], dc_fixpt_zero, 1618 dc_fixpt_one); 1619 1620 ++i; 1621 } 1622 } 1623 1624 static bool map_regamma_hw_to_x_user( 1625 const struct dc_gamma *ramp, 1626 struct pixel_gamma_point *coeff128, 1627 struct pwl_float_data *rgb_user, 1628 struct hw_x_point *coords_x, 1629 const struct gamma_pixel *axis_x, 1630 const struct pwl_float_data_ex *rgb_regamma, 1631 uint32_t hw_points_num, 1632 struct dc_transfer_func_distributed_points *tf_pts, 1633 bool map_user_ramp, 1634 bool do_clamping) 1635 { 1636 /* setup to spare calculated ideal regamma values */ 1637 1638 int i = 0; 1639 struct hw_x_point *coords = coords_x; 1640 const struct pwl_float_data_ex *regamma = rgb_regamma; 1641 1642 if (ramp && map_user_ramp) { 1643 copy_rgb_regamma_to_coordinates_x(coords, 1644 hw_points_num, 1645 rgb_regamma); 1646 1647 calculate_interpolated_hardware_curve( 1648 ramp, coeff128, rgb_user, coords, axis_x, 1649 hw_points_num, tf_pts); 1650 } else { 1651 /* just copy current rgb_regamma into tf_pts */ 1652 while (i <= hw_points_num) { 1653 tf_pts->red[i] = regamma->r; 1654 tf_pts->green[i] = regamma->g; 1655 tf_pts->blue[i] = regamma->b; 1656 1657 ++regamma; 1658 ++i; 1659 } 1660 } 1661 1662 if (do_clamping) { 1663 /* this should be named differently, all it does is clamp to 0-1 */ 1664 build_new_custom_resulted_curve(hw_points_num, tf_pts); 1665 } 1666 1667 return true; 1668 } 1669 1670 #define _EXTRA_POINTS 3 1671 1672 bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps, 1673 struct dc_transfer_func *input_tf, 1674 const struct dc_gamma *ramp, bool map_user_ramp) 1675 { 1676 struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts; 1677 struct dividers dividers; 1678 struct pwl_float_data *rgb_user = NULL; 1679 struct pwl_float_data_ex *curve = NULL; 1680 struct gamma_pixel *axis_x = NULL; 1681 struct pixel_gamma_point *coeff = NULL; 1682 enum dc_transfer_func_predefined tf; 1683 uint32_t i; 1684 bool ret = false; 1685 1686 if (input_tf->type == TF_TYPE_BYPASS) 1687 return false; 1688 1689 /* we can use hardcoded curve for plain SRGB TF 1690 * If linear, it's bypass if no user ramp 1691 */ 1692 if (input_tf->type == TF_TYPE_PREDEFINED) { 1693 if ((input_tf->tf == TRANSFER_FUNCTION_SRGB || 1694 input_tf->tf == TRANSFER_FUNCTION_LINEAR) && 1695 !map_user_ramp) 1696 return true; 1697 1698 if (dc_caps != NULL && 1699 dc_caps->dpp.dcn_arch == 1) { 1700 1701 if (input_tf->tf == TRANSFER_FUNCTION_PQ && 1702 dc_caps->dpp.dgam_rom_caps.pq == 1) 1703 return true; 1704 1705 if (input_tf->tf == TRANSFER_FUNCTION_GAMMA22 && 1706 dc_caps->dpp.dgam_rom_caps.gamma2_2 == 1) 1707 return true; 1708 1709 // HLG OOTF not accounted for 1710 if (input_tf->tf == TRANSFER_FUNCTION_HLG && 1711 dc_caps->dpp.dgam_rom_caps.hlg == 1) 1712 return true; 1713 } 1714 } 1715 1716 input_tf->type = TF_TYPE_DISTRIBUTED_POINTS; 1717 1718 if (map_user_ramp && ramp && ramp->type == GAMMA_RGB_256) { 1719 rgb_user = kvzalloc_objs(*rgb_user, 1720 ramp->num_entries + _EXTRA_POINTS); 1721 if (!rgb_user) 1722 goto rgb_user_alloc_fail; 1723 1724 axis_x = kvzalloc_objs(*axis_x, 1725 ramp->num_entries + _EXTRA_POINTS); 1726 if (!axis_x) 1727 goto axis_x_alloc_fail; 1728 1729 dividers.divider1 = dc_fixpt_from_fraction(3, 2); 1730 dividers.divider2 = dc_fixpt_from_int(2); 1731 dividers.divider3 = dc_fixpt_from_fraction(5, 2); 1732 1733 build_evenly_distributed_points( 1734 axis_x, 1735 ramp->num_entries, 1736 dividers); 1737 1738 scale_gamma(rgb_user, ramp, dividers); 1739 } 1740 1741 curve = kvzalloc_objs(*curve, MAX_HW_POINTS + _EXTRA_POINTS); 1742 if (!curve) 1743 goto curve_alloc_fail; 1744 1745 coeff = kvzalloc_objs(*coeff, MAX_HW_POINTS + _EXTRA_POINTS); 1746 if (!coeff) 1747 goto coeff_alloc_fail; 1748 1749 tf = input_tf->tf; 1750 1751 if (tf == TRANSFER_FUNCTION_PQ) 1752 build_de_pq(curve, 1753 MAX_HW_POINTS, 1754 coordinates_x); 1755 else if (tf == TRANSFER_FUNCTION_SRGB || 1756 tf == TRANSFER_FUNCTION_BT709 || 1757 tf == TRANSFER_FUNCTION_GAMMA22 || 1758 tf == TRANSFER_FUNCTION_GAMMA24 || 1759 tf == TRANSFER_FUNCTION_GAMMA26) 1760 build_degamma(curve, 1761 MAX_HW_POINTS, 1762 coordinates_x, 1763 tf); 1764 else if (tf == TRANSFER_FUNCTION_HLG) 1765 build_hlg_degamma(curve, 1766 MAX_HW_POINTS, 1767 coordinates_x, 1768 80, 1000); 1769 else if (tf == TRANSFER_FUNCTION_LINEAR) { 1770 // just copy coordinates_x into curve 1771 i = 0; 1772 while (i != MAX_HW_POINTS + 1) { 1773 curve[i].r = coordinates_x[i].x; 1774 curve[i].g = curve[i].r; 1775 curve[i].b = curve[i].r; 1776 i++; 1777 } 1778 } else 1779 goto invalid_tf_fail; 1780 1781 tf_pts->end_exponent = 0; 1782 tf_pts->x_point_at_y1_red = 1; 1783 tf_pts->x_point_at_y1_green = 1; 1784 tf_pts->x_point_at_y1_blue = 1; 1785 1786 if (input_tf->tf == TRANSFER_FUNCTION_PQ) { 1787 /* just copy current rgb_regamma into tf_pts */ 1788 struct pwl_float_data_ex *curvePt = curve; 1789 int i = 0; 1790 1791 while (i <= MAX_HW_POINTS) { 1792 tf_pts->red[i] = curvePt->r; 1793 tf_pts->green[i] = curvePt->g; 1794 tf_pts->blue[i] = curvePt->b; 1795 ++curvePt; 1796 ++i; 1797 } 1798 } else { 1799 // clamps to 0-1 1800 map_regamma_hw_to_x_user(ramp, coeff, rgb_user, 1801 coordinates_x, axis_x, curve, 1802 MAX_HW_POINTS, tf_pts, 1803 map_user_ramp && ramp && ramp->type == GAMMA_RGB_256, 1804 true); 1805 } 1806 1807 1808 1809 if (ramp && ramp->type == GAMMA_CUSTOM) 1810 apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); 1811 1812 ret = true; 1813 1814 invalid_tf_fail: 1815 kvfree(coeff); 1816 coeff_alloc_fail: 1817 kvfree(curve); 1818 curve_alloc_fail: 1819 kvfree(axis_x); 1820 axis_x_alloc_fail: 1821 kvfree(rgb_user); 1822 rgb_user_alloc_fail: 1823 1824 return ret; 1825 } 1826 1827 static bool calculate_curve(enum dc_transfer_func_predefined trans, 1828 struct dc_transfer_func_distributed_points *points, 1829 struct pwl_float_data_ex *rgb_regamma, 1830 const struct hdr_tm_params *fs_params, 1831 uint32_t sdr_ref_white_level, 1832 struct calculate_buffer *cal_buffer) 1833 { 1834 uint32_t i; 1835 bool ret = false; 1836 1837 if (trans == TRANSFER_FUNCTION_UNITY || 1838 trans == TRANSFER_FUNCTION_LINEAR) { 1839 points->end_exponent = 0; 1840 points->x_point_at_y1_red = 1; 1841 points->x_point_at_y1_green = 1; 1842 points->x_point_at_y1_blue = 1; 1843 1844 for (i = 0; i <= MAX_HW_POINTS ; i++) { 1845 rgb_regamma[i].r = coordinates_x[i].x; 1846 rgb_regamma[i].g = coordinates_x[i].x; 1847 rgb_regamma[i].b = coordinates_x[i].x; 1848 } 1849 1850 ret = true; 1851 } else if (trans == TRANSFER_FUNCTION_PQ) { 1852 points->end_exponent = 7; 1853 points->x_point_at_y1_red = 125; 1854 points->x_point_at_y1_green = 125; 1855 points->x_point_at_y1_blue = 125; 1856 1857 build_pq(rgb_regamma, 1858 MAX_HW_POINTS, 1859 coordinates_x, 1860 sdr_ref_white_level); 1861 1862 ret = true; 1863 } else if (trans == TRANSFER_FUNCTION_GAMMA22 && 1864 fs_params != NULL && fs_params->skip_tm == 0) { 1865 build_freesync_hdr(rgb_regamma, 1866 MAX_HW_POINTS, 1867 coordinates_x, 1868 fs_params, 1869 cal_buffer); 1870 1871 ret = true; 1872 } else if (trans == TRANSFER_FUNCTION_HLG) { 1873 points->end_exponent = 4; 1874 points->x_point_at_y1_red = 12; 1875 points->x_point_at_y1_green = 12; 1876 points->x_point_at_y1_blue = 12; 1877 1878 build_hlg_regamma(rgb_regamma, 1879 MAX_HW_POINTS, 1880 coordinates_x, 1881 80, 1000); 1882 1883 ret = true; 1884 } else { 1885 // trans == TRANSFER_FUNCTION_SRGB 1886 // trans == TRANSFER_FUNCTION_BT709 1887 // trans == TRANSFER_FUNCTION_GAMMA22 1888 // trans == TRANSFER_FUNCTION_GAMMA24 1889 // trans == TRANSFER_FUNCTION_GAMMA26 1890 points->end_exponent = 0; 1891 points->x_point_at_y1_red = 1; 1892 points->x_point_at_y1_green = 1; 1893 points->x_point_at_y1_blue = 1; 1894 1895 build_regamma(rgb_regamma, 1896 MAX_HW_POINTS, 1897 coordinates_x, 1898 trans, 1899 cal_buffer); 1900 1901 ret = true; 1902 } 1903 1904 return ret; 1905 } 1906 1907 bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, 1908 const struct dc_gamma *ramp, 1909 bool map_user_ramp, 1910 bool can_rom_be_used, 1911 const struct hdr_tm_params *fs_params, 1912 struct calculate_buffer *cal_buffer) 1913 { 1914 struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; 1915 struct dividers dividers; 1916 1917 struct pwl_float_data *rgb_user = NULL; 1918 struct pwl_float_data_ex *rgb_regamma = NULL; 1919 struct gamma_pixel *axis_x = NULL; 1920 struct pixel_gamma_point *coeff = NULL; 1921 enum dc_transfer_func_predefined tf; 1922 bool do_clamping = true; 1923 bool ret = false; 1924 1925 if (output_tf->type == TF_TYPE_BYPASS) 1926 return false; 1927 1928 /* we can use hardcoded curve for plain SRGB TF */ 1929 if (output_tf->type == TF_TYPE_PREDEFINED && can_rom_be_used == true && 1930 output_tf->tf == TRANSFER_FUNCTION_SRGB) { 1931 if (ramp == NULL) 1932 return true; 1933 if ((ramp->is_identity && ramp->type != GAMMA_CS_TFM_1D) || 1934 (!map_user_ramp && ramp->type == GAMMA_RGB_256)) 1935 return true; 1936 } 1937 1938 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; 1939 1940 if (ramp && ramp->type != GAMMA_CS_TFM_1D && 1941 (map_user_ramp || ramp->type != GAMMA_RGB_256)) { 1942 rgb_user = kvzalloc_objs(*rgb_user, 1943 ramp->num_entries + _EXTRA_POINTS); 1944 if (!rgb_user) 1945 goto rgb_user_alloc_fail; 1946 1947 axis_x = kvzalloc_objs(*axis_x, ramp->num_entries + 3); 1948 if (!axis_x) 1949 goto axis_x_alloc_fail; 1950 1951 dividers.divider1 = dc_fixpt_from_fraction(3, 2); 1952 dividers.divider2 = dc_fixpt_from_int(2); 1953 dividers.divider3 = dc_fixpt_from_fraction(5, 2); 1954 1955 build_evenly_distributed_points( 1956 axis_x, 1957 ramp->num_entries, 1958 dividers); 1959 1960 if (ramp->type == GAMMA_RGB_256 && map_user_ramp) 1961 scale_gamma(rgb_user, ramp, dividers); 1962 else if (ramp->type == GAMMA_RGB_FLOAT_1024) 1963 scale_gamma_dx(rgb_user, ramp, dividers); 1964 } 1965 1966 rgb_regamma = kvzalloc_objs(*rgb_regamma, MAX_HW_POINTS + _EXTRA_POINTS); 1967 if (!rgb_regamma) 1968 goto rgb_regamma_alloc_fail; 1969 1970 coeff = kvzalloc_objs(*coeff, MAX_HW_POINTS + _EXTRA_POINTS); 1971 if (!coeff) 1972 goto coeff_alloc_fail; 1973 1974 tf = output_tf->tf; 1975 1976 ret = calculate_curve(tf, 1977 tf_pts, 1978 rgb_regamma, 1979 fs_params, 1980 output_tf->sdr_ref_white_level, 1981 cal_buffer); 1982 1983 if (ret) { 1984 do_clamping = !(output_tf->tf == TRANSFER_FUNCTION_PQ) && 1985 !(output_tf->tf == TRANSFER_FUNCTION_GAMMA22 && 1986 fs_params != NULL && fs_params->skip_tm == 0); 1987 1988 map_regamma_hw_to_x_user(ramp, coeff, rgb_user, 1989 coordinates_x, axis_x, rgb_regamma, 1990 MAX_HW_POINTS, tf_pts, 1991 (map_user_ramp || (ramp && ramp->type != GAMMA_RGB_256)) && 1992 (ramp && ramp->type != GAMMA_CS_TFM_1D), 1993 do_clamping); 1994 1995 if (ramp && ramp->type == GAMMA_CS_TFM_1D) 1996 apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); 1997 } 1998 1999 kvfree(coeff); 2000 coeff_alloc_fail: 2001 kvfree(rgb_regamma); 2002 rgb_regamma_alloc_fail: 2003 kvfree(axis_x); 2004 axis_x_alloc_fail: 2005 kvfree(rgb_user); 2006 rgb_user_alloc_fail: 2007 return ret; 2008 } 2009