File: | dev/pci/drm/amd/display/modules/color/color_gamma.c |
Warning: | line 883, column 20 Value stored to 'a' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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_START224 224 |
36 | #define PRECISE_LUT_REGION_END239 239 |
37 | |
38 | static struct hw_x_point coordinates_x[MAX_HW_POINTS(16*32) + 2]; |
39 | |
40 | // these are helpers for calculations to reduce stack usage |
41 | // do not depend on these being preserved across calls |
42 | |
43 | /* Helper to optimize gamma calculation, only use in translate_from_linear, in |
44 | * particular the dc_fixpt_pow function which is very expensive |
45 | * The idea is that our regions for X points are exponential and currently they all use |
46 | * the same number of points (NUM_PTS_IN_REGION) and in each region every point |
47 | * is exactly 2x the one at the same index in the previous region. In other words |
48 | * X[i] = 2 * X[i-NUM_PTS_IN_REGION] for i>=16 |
49 | * The other fact is that (2x)^gamma = 2^gamma * x^gamma |
50 | * So we compute and save x^gamma for the first 16 regions, and for every next region |
51 | * just multiply with 2^gamma which can be computed once, and save the result so we |
52 | * recursively compute all the values. |
53 | */ |
54 | |
55 | /* |
56 | * Regamma coefficients are used for both regamma and degamma. Degamma |
57 | * coefficients are calculated in our formula using the regamma coefficients. |
58 | */ |
59 | /*sRGB 709 2.2 2.4 P3*/ |
60 | static const int32_t numerator01[] = { 31308, 180000, 0, 0, 0}; |
61 | static const int32_t numerator02[] = { 12920, 4500, 0, 0, 0}; |
62 | static const int32_t numerator03[] = { 55, 99, 0, 0, 0}; |
63 | static const int32_t numerator04[] = { 55, 99, 0, 0, 0}; |
64 | static const int32_t numerator05[] = { 2400, 2200, 2200, 2400, 2600}; |
65 | |
66 | /* one-time setup of X points */ |
67 | void setup_x_points_distribution(void) |
68 | { |
69 | struct fixed31_32 region_size = dc_fixpt_from_int(128); |
70 | int32_t segment; |
71 | uint32_t seg_offset; |
72 | uint32_t index; |
73 | struct fixed31_32 increment; |
74 | |
75 | coordinates_x[MAX_HW_POINTS(16*32)].x = region_size; |
76 | coordinates_x[MAX_HW_POINTS(16*32) + 1].x = region_size; |
77 | |
78 | for (segment = 6; segment > (6 - NUM_REGIONS32); segment--) { |
79 | region_size = dc_fixpt_div_int(region_size, 2); |
80 | increment = dc_fixpt_div_int(region_size, |
81 | NUM_PTS_IN_REGION16); |
82 | seg_offset = (segment + (NUM_REGIONS32 - 7)) * NUM_PTS_IN_REGION16; |
83 | coordinates_x[seg_offset].x = region_size; |
84 | |
85 | for (index = seg_offset + 1; |
86 | index < seg_offset + NUM_PTS_IN_REGION16; |
87 | index++) { |
88 | coordinates_x[index].x = dc_fixpt_add |
89 | (coordinates_x[index-1].x, increment); |
90 | } |
91 | } |
92 | } |
93 | |
94 | void log_x_points_distribution(struct dal_logger *logger) |
95 | { |
96 | int i = 0; |
97 | |
98 | if (logger != NULL((void *)0)) { |
99 | LOG_GAMMA_WRITE("Log X Distribution\n"); |
100 | |
101 | for (i = 0; i < MAX_HW_POINTS(16*32); i++) |
102 | LOG_GAMMA_WRITE("%llu\n", coordinates_x[i].x.value); |
103 | } |
104 | } |
105 | |
106 | static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) |
107 | { |
108 | /* consts for PQ gamma formula. */ |
109 | const struct fixed31_32 m1 = |
110 | dc_fixpt_from_fraction(159301758, 1000000000); |
111 | const struct fixed31_32 m2 = |
112 | dc_fixpt_from_fraction(7884375, 100000); |
113 | const struct fixed31_32 c1 = |
114 | dc_fixpt_from_fraction(8359375, 10000000); |
115 | const struct fixed31_32 c2 = |
116 | dc_fixpt_from_fraction(188515625, 10000000); |
117 | const struct fixed31_32 c3 = |
118 | dc_fixpt_from_fraction(186875, 10000); |
119 | |
120 | struct fixed31_32 l_pow_m1; |
121 | struct fixed31_32 base; |
122 | |
123 | if (dc_fixpt_lt(in_x, dc_fixpt_zero)) |
124 | in_x = dc_fixpt_zero; |
125 | |
126 | l_pow_m1 = dc_fixpt_pow(in_x, m1); |
127 | base = dc_fixpt_div( |
128 | dc_fixpt_add(c1, |
129 | (dc_fixpt_mul(c2, l_pow_m1))), |
130 | dc_fixpt_add(dc_fixpt_one, |
131 | (dc_fixpt_mul(c3, l_pow_m1)))); |
132 | *out_y = dc_fixpt_pow(base, m2); |
133 | } |
134 | |
135 | static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) |
136 | { |
137 | /* consts for dePQ gamma formula. */ |
138 | const struct fixed31_32 m1 = |
139 | dc_fixpt_from_fraction(159301758, 1000000000); |
140 | const struct fixed31_32 m2 = |
141 | dc_fixpt_from_fraction(7884375, 100000); |
142 | const struct fixed31_32 c1 = |
143 | dc_fixpt_from_fraction(8359375, 10000000); |
144 | const struct fixed31_32 c2 = |
145 | dc_fixpt_from_fraction(188515625, 10000000); |
146 | const struct fixed31_32 c3 = |
147 | dc_fixpt_from_fraction(186875, 10000); |
148 | |
149 | struct fixed31_32 l_pow_m1; |
150 | struct fixed31_32 base, div; |
151 | struct fixed31_32 base2; |
152 | |
153 | |
154 | if (dc_fixpt_lt(in_x, dc_fixpt_zero)) |
155 | in_x = dc_fixpt_zero; |
156 | |
157 | l_pow_m1 = dc_fixpt_pow(in_x, |
158 | dc_fixpt_div(dc_fixpt_one, m2)); |
159 | base = dc_fixpt_sub(l_pow_m1, c1); |
160 | |
161 | div = dc_fixpt_sub(c2, dc_fixpt_mul(c3, l_pow_m1)); |
162 | |
163 | base2 = dc_fixpt_div(base, div); |
164 | // avoid complex numbers |
165 | if (dc_fixpt_lt(base2, dc_fixpt_zero)) |
166 | base2 = dc_fixpt_sub(dc_fixpt_zero, base2); |
167 | |
168 | |
169 | *out_y = dc_fixpt_pow(base2, dc_fixpt_div(dc_fixpt_one, m1)); |
170 | |
171 | } |
172 | |
173 | |
174 | /* de gamma, non-linear to linear */ |
175 | static void compute_hlg_eotf(struct fixed31_32 in_x, |
176 | struct fixed31_32 *out_y, |
177 | uint32_t sdr_white_level, uint32_t max_luminance_nits) |
178 | { |
179 | struct fixed31_32 a; |
180 | struct fixed31_32 b; |
181 | struct fixed31_32 c; |
182 | struct fixed31_32 threshold; |
183 | struct fixed31_32 x; |
184 | |
185 | struct fixed31_32 scaling_factor = |
186 | dc_fixpt_from_fraction(max_luminance_nits, sdr_white_level); |
187 | a = dc_fixpt_from_fraction(17883277, 100000000); |
188 | b = dc_fixpt_from_fraction(28466892, 100000000); |
189 | c = dc_fixpt_from_fraction(55991073, 100000000); |
190 | threshold = dc_fixpt_from_fraction(1, 2); |
191 | |
192 | if (dc_fixpt_lt(in_x, threshold)) { |
193 | x = dc_fixpt_mul(in_x, in_x); |
194 | x = dc_fixpt_div_int(x, 3); |
195 | } else { |
196 | x = dc_fixpt_sub(in_x, c); |
197 | x = dc_fixpt_div(x, a); |
198 | x = dc_fixpt_exp(x); |
199 | x = dc_fixpt_add(x, b); |
200 | x = dc_fixpt_div_int(x, 12); |
201 | } |
202 | *out_y = dc_fixpt_mul(x, scaling_factor); |
203 | |
204 | } |
205 | |
206 | /* re gamma, linear to non-linear */ |
207 | static void compute_hlg_oetf(struct fixed31_32 in_x, struct fixed31_32 *out_y, |
208 | uint32_t sdr_white_level, uint32_t max_luminance_nits) |
209 | { |
210 | struct fixed31_32 a; |
211 | struct fixed31_32 b; |
212 | struct fixed31_32 c; |
213 | struct fixed31_32 threshold; |
214 | struct fixed31_32 x; |
215 | |
216 | struct fixed31_32 scaling_factor = |
217 | dc_fixpt_from_fraction(sdr_white_level, max_luminance_nits); |
218 | a = dc_fixpt_from_fraction(17883277, 100000000); |
219 | b = dc_fixpt_from_fraction(28466892, 100000000); |
220 | c = dc_fixpt_from_fraction(55991073, 100000000); |
221 | threshold = dc_fixpt_from_fraction(1, 12); |
222 | x = dc_fixpt_mul(in_x, scaling_factor); |
223 | |
224 | |
225 | if (dc_fixpt_lt(x, threshold)) { |
226 | x = dc_fixpt_mul(x, dc_fixpt_from_fraction(3, 1)); |
227 | *out_y = dc_fixpt_pow(x, dc_fixpt_half); |
228 | } else { |
229 | x = dc_fixpt_mul(x, dc_fixpt_from_fraction(12, 1)); |
230 | x = dc_fixpt_sub(x, b); |
231 | x = dc_fixpt_log(x); |
232 | x = dc_fixpt_mul(a, x); |
233 | *out_y = dc_fixpt_add(x, c); |
234 | } |
235 | } |
236 | |
237 | |
238 | /* one-time pre-compute PQ values - only for sdr_white_level 80 */ |
239 | void precompute_pq(void) |
240 | { |
241 | int i; |
242 | struct fixed31_32 x; |
243 | const struct hw_x_point *coord_x = coordinates_x + 32; |
244 | struct fixed31_32 scaling_factor = |
245 | dc_fixpt_from_fraction(80, 10000); |
246 | |
247 | struct fixed31_32 *pq_table = mod_color_get_table(type_pq_table); |
248 | |
249 | /* pow function has problems with arguments too small */ |
250 | for (i = 0; i < 32; i++) |
251 | pq_table[i] = dc_fixpt_zero; |
252 | |
253 | for (i = 32; i <= MAX_HW_POINTS(16*32); i++) { |
254 | x = dc_fixpt_mul(coord_x->x, scaling_factor); |
255 | compute_pq(x, &pq_table[i]); |
256 | ++coord_x; |
257 | } |
258 | } |
259 | |
260 | /* one-time pre-compute dePQ values - only for max pixel value 125 FP16 */ |
261 | void precompute_de_pq(void) |
262 | { |
263 | int i; |
264 | struct fixed31_32 y; |
265 | uint32_t begin_index, end_index; |
266 | |
267 | struct fixed31_32 scaling_factor = dc_fixpt_from_int(125); |
268 | struct fixed31_32 *de_pq_table = mod_color_get_table(type_de_pq_table); |
269 | /* X points is 2^-25 to 2^7 |
270 | * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions |
271 | */ |
272 | begin_index = 13 * NUM_PTS_IN_REGION16; |
273 | end_index = begin_index + 12 * NUM_PTS_IN_REGION16; |
274 | |
275 | for (i = 0; i <= begin_index; i++) |
276 | de_pq_table[i] = dc_fixpt_zero; |
277 | |
278 | for (; i <= end_index; i++) { |
279 | compute_de_pq(coordinates_x[i].x, &y); |
280 | de_pq_table[i] = dc_fixpt_mul(y, scaling_factor); |
281 | } |
282 | |
283 | for (; i <= MAX_HW_POINTS(16*32); i++) |
284 | de_pq_table[i] = de_pq_table[i-1]; |
285 | } |
286 | struct dividers { |
287 | struct fixed31_32 divider1; |
288 | struct fixed31_32 divider2; |
289 | struct fixed31_32 divider3; |
290 | }; |
291 | |
292 | |
293 | static bool_Bool build_coefficients(struct gamma_coefficients *coefficients, |
294 | enum dc_transfer_func_predefined type) |
295 | { |
296 | |
297 | uint32_t i = 0; |
298 | uint32_t index = 0; |
299 | bool_Bool ret = true1; |
300 | |
301 | if (type == TRANSFER_FUNCTION_SRGB) |
302 | index = 0; |
303 | else if (type == TRANSFER_FUNCTION_BT709) |
304 | index = 1; |
305 | else if (type == TRANSFER_FUNCTION_GAMMA22) |
306 | index = 2; |
307 | else if (type == TRANSFER_FUNCTION_GAMMA24) |
308 | index = 3; |
309 | else if (type == TRANSFER_FUNCTION_GAMMA26) |
310 | index = 4; |
311 | else { |
312 | ret = false0; |
313 | goto release; |
314 | } |
315 | |
316 | do { |
317 | coefficients->a0[i] = dc_fixpt_from_fraction( |
318 | numerator01[index], 10000000); |
319 | coefficients->a1[i] = dc_fixpt_from_fraction( |
320 | numerator02[index], 1000); |
321 | coefficients->a2[i] = dc_fixpt_from_fraction( |
322 | numerator03[index], 1000); |
323 | coefficients->a3[i] = dc_fixpt_from_fraction( |
324 | numerator04[index], 1000); |
325 | coefficients->user_gamma[i] = dc_fixpt_from_fraction( |
326 | numerator05[index], 1000); |
327 | |
328 | ++i; |
329 | } while (i != ARRAY_SIZE(coefficients->a0)(sizeof((coefficients->a0)) / sizeof((coefficients->a0) [0]))); |
330 | release: |
331 | return ret; |
332 | } |
333 | |
334 | static struct fixed31_32 translate_from_linear_space( |
335 | struct translate_from_linear_space_args *args) |
336 | { |
337 | const struct fixed31_32 one = dc_fixpt_from_int(1); |
338 | |
339 | struct fixed31_32 scratch_1, scratch_2; |
340 | struct calculate_buffer *cal_buffer = args->cal_buffer; |
341 | |
342 | if (dc_fixpt_le(one, args->arg)) |
343 | return one; |
344 | |
345 | if (dc_fixpt_le(args->arg, dc_fixpt_neg(args->a0))) { |
346 | scratch_1 = dc_fixpt_add(one, args->a3); |
347 | scratch_2 = dc_fixpt_pow( |
348 | dc_fixpt_neg(args->arg), |
349 | dc_fixpt_recip(args->gamma)); |
350 | scratch_1 = dc_fixpt_mul(scratch_1, scratch_2); |
351 | scratch_1 = dc_fixpt_sub(args->a2, scratch_1); |
352 | |
353 | return scratch_1; |
354 | } else if (dc_fixpt_le(args->a0, args->arg)) { |
355 | if (cal_buffer->buffer_index == 0) { |
356 | cal_buffer->gamma_of_2 = dc_fixpt_pow(dc_fixpt_from_int(2), |
357 | dc_fixpt_recip(args->gamma)); |
358 | } |
359 | scratch_1 = dc_fixpt_add(one, args->a3); |
360 | /* In the first region (first 16 points) and in the |
361 | * region delimited by START/END we calculate with |
362 | * full precision to avoid error accumulation. |
363 | */ |
364 | if ((cal_buffer->buffer_index >= PRECISE_LUT_REGION_START224 && |
365 | cal_buffer->buffer_index <= PRECISE_LUT_REGION_END239) || |
366 | (cal_buffer->buffer_index < 16)) |
367 | scratch_2 = dc_fixpt_pow(args->arg, |
368 | dc_fixpt_recip(args->gamma)); |
369 | else |
370 | scratch_2 = dc_fixpt_mul(cal_buffer->gamma_of_2, |
371 | cal_buffer->buffer[cal_buffer->buffer_index%16]); |
372 | |
373 | if (cal_buffer->buffer_index != -1) { |
374 | cal_buffer->buffer[cal_buffer->buffer_index%16] = scratch_2; |
375 | cal_buffer->buffer_index++; |
376 | } |
377 | |
378 | scratch_1 = dc_fixpt_mul(scratch_1, scratch_2); |
379 | scratch_1 = dc_fixpt_sub(scratch_1, args->a2); |
380 | |
381 | return scratch_1; |
382 | } |
383 | else |
384 | return dc_fixpt_mul(args->arg, args->a1); |
385 | } |
386 | |
387 | |
388 | static struct fixed31_32 translate_from_linear_space_long( |
389 | struct translate_from_linear_space_args *args) |
390 | { |
391 | const struct fixed31_32 one = dc_fixpt_from_int(1); |
392 | |
393 | if (dc_fixpt_lt(one, args->arg)) |
394 | return one; |
395 | |
396 | if (dc_fixpt_le(args->arg, dc_fixpt_neg(args->a0))) |
397 | return dc_fixpt_sub( |
398 | args->a2, |
399 | dc_fixpt_mul( |
400 | dc_fixpt_add( |
401 | one, |
402 | args->a3), |
403 | dc_fixpt_pow( |
404 | dc_fixpt_neg(args->arg), |
405 | dc_fixpt_recip(args->gamma)))); |
406 | else if (dc_fixpt_le(args->a0, args->arg)) |
407 | return dc_fixpt_sub( |
408 | dc_fixpt_mul( |
409 | dc_fixpt_add( |
410 | one, |
411 | args->a3), |
412 | dc_fixpt_pow( |
413 | args->arg, |
414 | dc_fixpt_recip(args->gamma))), |
415 | args->a2); |
416 | else |
417 | return dc_fixpt_mul(args->arg, args->a1); |
418 | } |
419 | |
420 | static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg, bool_Bool use_eetf, struct calculate_buffer *cal_buffer) |
421 | { |
422 | struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10); |
423 | struct translate_from_linear_space_args scratch_gamma_args; |
424 | |
425 | scratch_gamma_args.arg = arg; |
426 | scratch_gamma_args.a0 = dc_fixpt_zero; |
427 | scratch_gamma_args.a1 = dc_fixpt_zero; |
428 | scratch_gamma_args.a2 = dc_fixpt_zero; |
429 | scratch_gamma_args.a3 = dc_fixpt_zero; |
430 | scratch_gamma_args.cal_buffer = cal_buffer; |
431 | scratch_gamma_args.gamma = gamma; |
432 | |
433 | if (use_eetf) |
434 | return translate_from_linear_space_long(&scratch_gamma_args); |
435 | |
436 | return translate_from_linear_space(&scratch_gamma_args); |
437 | } |
438 | |
439 | |
440 | static struct fixed31_32 translate_to_linear_space( |
441 | struct fixed31_32 arg, |
442 | struct fixed31_32 a0, |
443 | struct fixed31_32 a1, |
444 | struct fixed31_32 a2, |
445 | struct fixed31_32 a3, |
446 | struct fixed31_32 gamma) |
447 | { |
448 | struct fixed31_32 linear; |
449 | |
450 | a0 = dc_fixpt_mul(a0, a1); |
451 | if (dc_fixpt_le(arg, dc_fixpt_neg(a0))) |
452 | |
453 | linear = dc_fixpt_neg( |
454 | dc_fixpt_pow( |
455 | dc_fixpt_div( |
456 | dc_fixpt_sub(a2, arg), |
457 | dc_fixpt_add( |
458 | dc_fixpt_one, a3)), gamma)); |
459 | |
460 | else if (dc_fixpt_le(dc_fixpt_neg(a0), arg) && |
461 | dc_fixpt_le(arg, a0)) |
462 | linear = dc_fixpt_div(arg, a1); |
463 | else |
464 | linear = dc_fixpt_pow( |
465 | dc_fixpt_div( |
466 | dc_fixpt_add(a2, arg), |
467 | dc_fixpt_add( |
468 | dc_fixpt_one, a3)), gamma); |
469 | |
470 | return linear; |
471 | } |
472 | |
473 | static struct fixed31_32 translate_from_linear_space_ex( |
474 | struct fixed31_32 arg, |
475 | struct gamma_coefficients *coeff, |
476 | uint32_t color_index, |
477 | struct calculate_buffer *cal_buffer) |
478 | { |
479 | struct translate_from_linear_space_args scratch_gamma_args; |
480 | |
481 | scratch_gamma_args.arg = arg; |
482 | scratch_gamma_args.a0 = coeff->a0[color_index]; |
483 | scratch_gamma_args.a1 = coeff->a1[color_index]; |
484 | scratch_gamma_args.a2 = coeff->a2[color_index]; |
485 | scratch_gamma_args.a3 = coeff->a3[color_index]; |
486 | scratch_gamma_args.gamma = coeff->user_gamma[color_index]; |
487 | scratch_gamma_args.cal_buffer = cal_buffer; |
488 | |
489 | return translate_from_linear_space(&scratch_gamma_args); |
490 | } |
491 | |
492 | |
493 | static inline struct fixed31_32 translate_to_linear_space_ex( |
494 | struct fixed31_32 arg, |
495 | struct gamma_coefficients *coeff, |
496 | uint32_t color_index) |
497 | { |
498 | return translate_to_linear_space( |
499 | arg, |
500 | coeff->a0[color_index], |
501 | coeff->a1[color_index], |
502 | coeff->a2[color_index], |
503 | coeff->a3[color_index], |
504 | coeff->user_gamma[color_index]); |
505 | } |
506 | |
507 | |
508 | static bool_Bool find_software_points( |
509 | const struct dc_gamma *ramp, |
510 | const struct gamma_pixel *axis_x, |
511 | struct fixed31_32 hw_point, |
512 | enum channel_name channel, |
513 | uint32_t *index_to_start, |
514 | uint32_t *index_left, |
515 | uint32_t *index_right, |
516 | enum hw_point_position *pos) |
517 | { |
518 | const uint32_t max_number = ramp->num_entries + 3; |
519 | |
520 | struct fixed31_32 left, right; |
521 | |
522 | uint32_t i = *index_to_start; |
523 | |
524 | while (i < max_number) { |
525 | if (channel == CHANNEL_NAME_RED) { |
526 | left = axis_x[i].r; |
527 | |
528 | if (i < max_number - 1) |
529 | right = axis_x[i + 1].r; |
530 | else |
531 | right = axis_x[max_number - 1].r; |
532 | } else if (channel == CHANNEL_NAME_GREEN) { |
533 | left = axis_x[i].g; |
534 | |
535 | if (i < max_number - 1) |
536 | right = axis_x[i + 1].g; |
537 | else |
538 | right = axis_x[max_number - 1].g; |
539 | } else { |
540 | left = axis_x[i].b; |
541 | |
542 | if (i < max_number - 1) |
543 | right = axis_x[i + 1].b; |
544 | else |
545 | right = axis_x[max_number - 1].b; |
546 | } |
547 | |
548 | if (dc_fixpt_le(left, hw_point) && |
549 | dc_fixpt_le(hw_point, right)) { |
550 | *index_to_start = i; |
551 | *index_left = i; |
552 | |
553 | if (i < max_number - 1) |
554 | *index_right = i + 1; |
555 | else |
556 | *index_right = max_number - 1; |
557 | |
558 | *pos = HW_POINT_POSITION_MIDDLE; |
559 | |
560 | return true1; |
561 | } else if ((i == *index_to_start) && |
562 | dc_fixpt_le(hw_point, left)) { |
563 | *index_to_start = i; |
564 | *index_left = i; |
565 | *index_right = i; |
566 | |
567 | *pos = HW_POINT_POSITION_LEFT; |
568 | |
569 | return true1; |
570 | } else if ((i == max_number - 1) && |
571 | dc_fixpt_le(right, hw_point)) { |
572 | *index_to_start = i; |
573 | *index_left = i; |
574 | *index_right = i; |
575 | |
576 | *pos = HW_POINT_POSITION_RIGHT; |
577 | |
578 | return true1; |
579 | } |
580 | |
581 | ++i; |
582 | } |
583 | |
584 | return false0; |
585 | } |
586 | |
587 | static bool_Bool build_custom_gamma_mapping_coefficients_worker( |
588 | const struct dc_gamma *ramp, |
589 | struct pixel_gamma_point *coeff, |
590 | const struct hw_x_point *coordinates_x, |
591 | const struct gamma_pixel *axis_x, |
592 | enum channel_name channel, |
593 | uint32_t number_of_points) |
594 | { |
595 | uint32_t i = 0; |
596 | |
597 | while (i <= number_of_points) { |
598 | struct fixed31_32 coord_x; |
599 | |
600 | uint32_t index_to_start = 0; |
601 | uint32_t index_left = 0; |
602 | uint32_t index_right = 0; |
603 | |
604 | enum hw_point_position hw_pos; |
605 | |
606 | struct gamma_point *point; |
607 | |
608 | struct fixed31_32 left_pos; |
609 | struct fixed31_32 right_pos; |
610 | |
611 | if (channel == CHANNEL_NAME_RED) |
612 | coord_x = coordinates_x[i].regamma_y_red; |
613 | else if (channel == CHANNEL_NAME_GREEN) |
614 | coord_x = coordinates_x[i].regamma_y_green; |
615 | else |
616 | coord_x = coordinates_x[i].regamma_y_blue; |
617 | |
618 | if (!find_software_points( |
619 | ramp, axis_x, coord_x, channel, |
620 | &index_to_start, &index_left, &index_right, &hw_pos)) { |
621 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 621); do {} while (0); } while (0); |
622 | return false0; |
623 | } |
624 | |
625 | if (index_left >= ramp->num_entries + 3) { |
626 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 626); do {} while (0); } while (0); |
627 | return false0; |
628 | } |
629 | |
630 | if (index_right >= ramp->num_entries + 3) { |
631 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 631); do {} while (0); } while (0); |
632 | return false0; |
633 | } |
634 | |
635 | if (channel == CHANNEL_NAME_RED) { |
636 | point = &coeff[i].r; |
637 | |
638 | left_pos = axis_x[index_left].r; |
639 | right_pos = axis_x[index_right].r; |
640 | } else if (channel == CHANNEL_NAME_GREEN) { |
641 | point = &coeff[i].g; |
642 | |
643 | left_pos = axis_x[index_left].g; |
644 | right_pos = axis_x[index_right].g; |
645 | } else { |
646 | point = &coeff[i].b; |
647 | |
648 | left_pos = axis_x[index_left].b; |
649 | right_pos = axis_x[index_right].b; |
650 | } |
651 | |
652 | if (hw_pos == HW_POINT_POSITION_MIDDLE) |
653 | point->coeff = dc_fixpt_div( |
654 | dc_fixpt_sub( |
655 | coord_x, |
656 | left_pos), |
657 | dc_fixpt_sub( |
658 | right_pos, |
659 | left_pos)); |
660 | else if (hw_pos == HW_POINT_POSITION_LEFT) |
661 | point->coeff = dc_fixpt_zero; |
662 | else if (hw_pos == HW_POINT_POSITION_RIGHT) |
663 | point->coeff = dc_fixpt_from_int(2); |
664 | else { |
665 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 665); do {} while (0); } while (0); |
666 | return false0; |
667 | } |
668 | |
669 | point->left_index = index_left; |
670 | point->right_index = index_right; |
671 | point->pos = hw_pos; |
672 | |
673 | ++i; |
674 | } |
675 | |
676 | return true1; |
677 | } |
678 | |
679 | static struct fixed31_32 calculate_mapped_value( |
680 | struct pwl_float_data *rgb, |
681 | const struct pixel_gamma_point *coeff, |
682 | enum channel_name channel, |
683 | uint32_t max_index) |
684 | { |
685 | const struct gamma_point *point; |
686 | |
687 | struct fixed31_32 result; |
688 | |
689 | if (channel == CHANNEL_NAME_RED) |
690 | point = &coeff->r; |
691 | else if (channel == CHANNEL_NAME_GREEN) |
692 | point = &coeff->g; |
693 | else |
694 | point = &coeff->b; |
695 | |
696 | if ((point->left_index < 0) || (point->left_index > max_index)) { |
697 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 697); do {} while (0); } while (0); |
698 | return dc_fixpt_zero; |
699 | } |
700 | |
701 | if ((point->right_index < 0) || (point->right_index > max_index)) { |
702 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 702); do {} while (0); } while (0); |
703 | return dc_fixpt_zero; |
704 | } |
705 | |
706 | if (point->pos == HW_POINT_POSITION_MIDDLE) |
707 | if (channel == CHANNEL_NAME_RED) |
708 | result = dc_fixpt_add( |
709 | dc_fixpt_mul( |
710 | point->coeff, |
711 | dc_fixpt_sub( |
712 | rgb[point->right_index].r, |
713 | rgb[point->left_index].r)), |
714 | rgb[point->left_index].r); |
715 | else if (channel == CHANNEL_NAME_GREEN) |
716 | result = dc_fixpt_add( |
717 | dc_fixpt_mul( |
718 | point->coeff, |
719 | dc_fixpt_sub( |
720 | rgb[point->right_index].g, |
721 | rgb[point->left_index].g)), |
722 | rgb[point->left_index].g); |
723 | else |
724 | result = dc_fixpt_add( |
725 | dc_fixpt_mul( |
726 | point->coeff, |
727 | dc_fixpt_sub( |
728 | rgb[point->right_index].b, |
729 | rgb[point->left_index].b)), |
730 | rgb[point->left_index].b); |
731 | else if (point->pos == HW_POINT_POSITION_LEFT) { |
732 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 732); do {} while (0); } while (0); |
733 | result = dc_fixpt_zero; |
734 | } else { |
735 | result = dc_fixpt_one; |
736 | } |
737 | |
738 | return result; |
739 | } |
740 | |
741 | static void build_pq(struct pwl_float_data_ex *rgb_regamma, |
742 | uint32_t hw_points_num, |
743 | const struct hw_x_point *coordinate_x, |
744 | uint32_t sdr_white_level) |
745 | { |
746 | uint32_t i, start_index; |
747 | |
748 | struct pwl_float_data_ex *rgb = rgb_regamma; |
749 | const struct hw_x_point *coord_x = coordinate_x; |
750 | struct fixed31_32 x; |
751 | struct fixed31_32 output; |
752 | struct fixed31_32 scaling_factor = |
753 | dc_fixpt_from_fraction(sdr_white_level, 10000); |
754 | struct fixed31_32 *pq_table = mod_color_get_table(type_pq_table); |
755 | |
756 | if (!mod_color_is_table_init(type_pq_table) && sdr_white_level == 80) { |
757 | precompute_pq(); |
758 | mod_color_set_table_init_state(type_pq_table, true1); |
759 | } |
760 | |
761 | /* TODO: start index is from segment 2^-24, skipping first segment |
762 | * due to x values too small for power calculations |
763 | */ |
764 | start_index = 32; |
765 | rgb += start_index; |
766 | coord_x += start_index; |
767 | |
768 | for (i = start_index; i <= hw_points_num; i++) { |
769 | /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125. |
770 | * FP 1.0 = 80nits |
771 | */ |
772 | if (sdr_white_level == 80) { |
773 | output = pq_table[i]; |
774 | } else { |
775 | x = dc_fixpt_mul(coord_x->x, scaling_factor); |
776 | compute_pq(x, &output); |
777 | } |
778 | |
779 | /* should really not happen? */ |
780 | if (dc_fixpt_lt(output, dc_fixpt_zero)) |
781 | output = dc_fixpt_zero; |
782 | else if (dc_fixpt_lt(dc_fixpt_one, output)) |
783 | output = dc_fixpt_one; |
784 | |
785 | rgb->r = output; |
786 | rgb->g = output; |
787 | rgb->b = output; |
788 | |
789 | ++coord_x; |
790 | ++rgb; |
791 | } |
792 | } |
793 | |
794 | static void build_de_pq(struct pwl_float_data_ex *de_pq, |
795 | uint32_t hw_points_num, |
796 | const struct hw_x_point *coordinate_x) |
797 | { |
798 | uint32_t i; |
799 | struct fixed31_32 output; |
800 | struct fixed31_32 *de_pq_table = mod_color_get_table(type_de_pq_table); |
801 | struct fixed31_32 scaling_factor = dc_fixpt_from_int(125); |
802 | |
803 | if (!mod_color_is_table_init(type_de_pq_table)) { |
804 | precompute_de_pq(); |
805 | mod_color_set_table_init_state(type_de_pq_table, true1); |
806 | } |
807 | |
808 | |
809 | for (i = 0; i <= hw_points_num; i++) { |
810 | output = de_pq_table[i]; |
811 | /* should really not happen? */ |
812 | if (dc_fixpt_lt(output, dc_fixpt_zero)) |
813 | output = dc_fixpt_zero; |
814 | else if (dc_fixpt_lt(scaling_factor, output)) |
815 | output = scaling_factor; |
816 | de_pq[i].r = output; |
817 | de_pq[i].g = output; |
818 | de_pq[i].b = output; |
819 | } |
820 | } |
821 | |
822 | static bool_Bool build_regamma(struct pwl_float_data_ex *rgb_regamma, |
823 | uint32_t hw_points_num, |
824 | const struct hw_x_point *coordinate_x, |
825 | enum dc_transfer_func_predefined type, |
826 | struct calculate_buffer *cal_buffer) |
827 | { |
828 | uint32_t i; |
829 | bool_Bool ret = false0; |
830 | |
831 | struct gamma_coefficients *coeff; |
832 | struct pwl_float_data_ex *rgb = rgb_regamma; |
833 | const struct hw_x_point *coord_x = coordinate_x; |
834 | |
835 | coeff = kvzalloc(sizeof(*coeff), GFP_KERNEL(0x0001 | 0x0004)); |
836 | if (!coeff) |
837 | goto release; |
838 | |
839 | if (!build_coefficients(coeff, type)) |
840 | goto release; |
841 | |
842 | memset(cal_buffer->buffer, 0, NUM_PTS_IN_REGION * sizeof(struct fixed31_32))__builtin_memset((cal_buffer->buffer), (0), (16 * sizeof(struct fixed31_32))); |
843 | cal_buffer->buffer_index = 0; // see variable definition for more info |
844 | |
845 | i = 0; |
846 | while (i <= hw_points_num) { |
847 | /* TODO use y vs r,g,b */ |
848 | rgb->r = translate_from_linear_space_ex( |
849 | coord_x->x, coeff, 0, cal_buffer); |
850 | rgb->g = rgb->r; |
851 | rgb->b = rgb->r; |
852 | ++coord_x; |
853 | ++rgb; |
854 | ++i; |
855 | } |
856 | cal_buffer->buffer_index = -1; |
857 | ret = true1; |
858 | release: |
859 | kvfree(coeff); |
860 | return ret; |
861 | } |
862 | |
863 | static void hermite_spline_eetf(struct fixed31_32 input_x, |
864 | struct fixed31_32 max_display, |
865 | struct fixed31_32 min_display, |
866 | struct fixed31_32 max_content, |
867 | struct fixed31_32 *out_x) |
868 | { |
869 | struct fixed31_32 min_lum_pq; |
870 | struct fixed31_32 max_lum_pq; |
871 | struct fixed31_32 max_content_pq; |
872 | struct fixed31_32 ks; |
873 | struct fixed31_32 E1; |
874 | struct fixed31_32 E2; |
875 | struct fixed31_32 E3; |
876 | struct fixed31_32 t; |
877 | struct fixed31_32 t2; |
878 | struct fixed31_32 t3; |
879 | struct fixed31_32 two; |
880 | struct fixed31_32 three; |
881 | struct fixed31_32 temp1; |
882 | struct fixed31_32 temp2; |
883 | struct fixed31_32 a = dc_fixpt_from_fraction(15, 10); |
Value stored to 'a' during its initialization is never read | |
884 | struct fixed31_32 b = dc_fixpt_from_fraction(5, 10); |
885 | struct fixed31_32 epsilon = dc_fixpt_from_fraction(1, 1000000); // dc_fixpt_epsilon is a bit too small |
886 | |
887 | if (dc_fixpt_eq(max_content, dc_fixpt_zero)) { |
888 | *out_x = dc_fixpt_zero; |
889 | return; |
890 | } |
891 | |
892 | compute_pq(input_x, &E1); |
893 | compute_pq(dc_fixpt_div(min_display, max_content), &min_lum_pq); |
894 | compute_pq(dc_fixpt_div(max_display, max_content), &max_lum_pq); |
895 | compute_pq(dc_fixpt_one, &max_content_pq); // always 1? DAL2 code is weird |
896 | a = dc_fixpt_div(dc_fixpt_add(dc_fixpt_one, b), max_content_pq); // (1+b)/maxContent |
897 | ks = dc_fixpt_sub(dc_fixpt_mul(a, max_lum_pq), b); // a * max_lum_pq - b |
898 | |
899 | if (dc_fixpt_lt(E1, ks)) |
900 | E2 = E1; |
901 | else if (dc_fixpt_le(ks, E1) && dc_fixpt_le(E1, dc_fixpt_one)) { |
902 | if (dc_fixpt_lt(epsilon, dc_fixpt_sub(dc_fixpt_one, ks))) |
903 | // t = (E1 - ks) / (1 - ks) |
904 | t = dc_fixpt_div(dc_fixpt_sub(E1, ks), |
905 | dc_fixpt_sub(dc_fixpt_one, ks)); |
906 | else |
907 | t = dc_fixpt_zero; |
908 | |
909 | two = dc_fixpt_from_int(2); |
910 | three = dc_fixpt_from_int(3); |
911 | |
912 | t2 = dc_fixpt_mul(t, t); |
913 | t3 = dc_fixpt_mul(t2, t); |
914 | temp1 = dc_fixpt_mul(two, t3); |
915 | temp2 = dc_fixpt_mul(three, t2); |
916 | |
917 | // (2t^3 - 3t^2 + 1) * ks |
918 | E2 = dc_fixpt_mul(ks, dc_fixpt_add(dc_fixpt_one, |
919 | dc_fixpt_sub(temp1, temp2))); |
920 | |
921 | // (-2t^3 + 3t^2) * max_lum_pq |
922 | E2 = dc_fixpt_add(E2, dc_fixpt_mul(max_lum_pq, |
923 | dc_fixpt_sub(temp2, temp1))); |
924 | |
925 | temp1 = dc_fixpt_mul(two, t2); |
926 | temp2 = dc_fixpt_sub(dc_fixpt_one, ks); |
927 | |
928 | // (t^3 - 2t^2 + t) * (1-ks) |
929 | E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2, |
930 | dc_fixpt_add(t, dc_fixpt_sub(t3, temp1)))); |
931 | } else |
932 | E2 = dc_fixpt_one; |
933 | |
934 | temp1 = dc_fixpt_sub(dc_fixpt_one, E2); |
935 | temp2 = dc_fixpt_mul(temp1, temp1); |
936 | temp2 = dc_fixpt_mul(temp2, temp2); |
937 | // temp2 = (1-E2)^4 |
938 | |
939 | E3 = dc_fixpt_add(E2, dc_fixpt_mul(min_lum_pq, temp2)); |
940 | compute_de_pq(E3, out_x); |
941 | |
942 | *out_x = dc_fixpt_div(*out_x, dc_fixpt_div(max_display, max_content)); |
943 | } |
944 | |
945 | static bool_Bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, |
946 | uint32_t hw_points_num, |
947 | const struct hw_x_point *coordinate_x, |
948 | const struct hdr_tm_params *fs_params, |
949 | struct calculate_buffer *cal_buffer) |
950 | { |
951 | uint32_t i; |
952 | struct pwl_float_data_ex *rgb = rgb_regamma; |
953 | const struct hw_x_point *coord_x = coordinate_x; |
954 | const struct hw_x_point *prv_coord_x = coord_x; |
955 | struct fixed31_32 scaledX = dc_fixpt_zero; |
956 | struct fixed31_32 scaledX1 = dc_fixpt_zero; |
957 | struct fixed31_32 max_display; |
958 | struct fixed31_32 min_display; |
959 | struct fixed31_32 max_content; |
960 | struct fixed31_32 clip = dc_fixpt_one; |
961 | struct fixed31_32 output; |
962 | bool_Bool use_eetf = false0; |
963 | bool_Bool is_clipped = false0; |
964 | struct fixed31_32 sdr_white_level; |
965 | struct fixed31_32 coordX_diff; |
966 | struct fixed31_32 out_dist_max; |
967 | struct fixed31_32 bright_norm; |
968 | |
969 | if (fs_params->max_content == 0 || |
970 | fs_params->max_display == 0) |
971 | return false0; |
972 | |
973 | max_display = dc_fixpt_from_int(fs_params->max_display); |
974 | min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000); |
975 | max_content = dc_fixpt_from_int(fs_params->max_content); |
976 | sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level); |
977 | |
978 | if (fs_params->min_display > 1000) // cap at 0.1 at the bottom |
979 | min_display = dc_fixpt_from_fraction(1, 10); |
980 | if (fs_params->max_display < 100) // cap at 100 at the top |
981 | max_display = dc_fixpt_from_int(100); |
982 | |
983 | // only max used, we don't adjust min luminance |
984 | if (fs_params->max_content > fs_params->max_display) |
985 | use_eetf = true1; |
986 | else |
987 | max_content = max_display; |
988 | |
989 | if (!use_eetf) |
990 | cal_buffer->buffer_index = 0; // see var definition for more info |
991 | rgb += 32; // first 32 points have problems with fixed point, too small |
992 | coord_x += 32; |
993 | |
994 | for (i = 32; i <= hw_points_num; i++) { |
995 | if (!is_clipped) { |
996 | if (use_eetf) { |
997 | /* max content is equal 1 */ |
998 | scaledX1 = dc_fixpt_div(coord_x->x, |
999 | dc_fixpt_div(max_content, sdr_white_level)); |
1000 | hermite_spline_eetf(scaledX1, max_display, min_display, |
1001 | max_content, &scaledX); |
1002 | } else |
1003 | scaledX = dc_fixpt_div(coord_x->x, |
1004 | dc_fixpt_div(max_display, sdr_white_level)); |
1005 | |
1006 | if (dc_fixpt_lt(scaledX, clip)) { |
1007 | if (dc_fixpt_lt(scaledX, dc_fixpt_zero)) |
1008 | output = dc_fixpt_zero; |
1009 | else |
1010 | output = calculate_gamma22(scaledX, use_eetf, cal_buffer); |
1011 | |
1012 | // Ensure output respects reasonable boundaries |
1013 | output = dc_fixpt_clamp(output, dc_fixpt_zero, dc_fixpt_one); |
1014 | |
1015 | rgb->r = output; |
1016 | rgb->g = output; |
1017 | rgb->b = output; |
1018 | } else { |
1019 | /* Here clipping happens for the first time */ |
1020 | is_clipped = true1; |
1021 | |
1022 | /* The next few lines implement the equation |
1023 | * output = prev_out + |
1024 | * (coord_x->x - prev_coord_x->x) * |
1025 | * (1.0 - prev_out) / |
1026 | * (maxDisp/sdr_white_level - prevCoordX) |
1027 | * |
1028 | * This equation interpolates the first point |
1029 | * after max_display/80 so that the slope from |
1030 | * hw_x_before_max and hw_x_after_max is such |
1031 | * that we hit Y=1.0 at max_display/80. |
1032 | */ |
1033 | |
1034 | coordX_diff = dc_fixpt_sub(coord_x->x, prv_coord_x->x); |
1035 | out_dist_max = dc_fixpt_sub(dc_fixpt_one, output); |
1036 | bright_norm = dc_fixpt_div(max_display, sdr_white_level); |
1037 | |
1038 | output = dc_fixpt_add( |
1039 | output, dc_fixpt_mul( |
1040 | coordX_diff, dc_fixpt_div( |
1041 | out_dist_max, |
1042 | dc_fixpt_sub(bright_norm, prv_coord_x->x) |
1043 | ) |
1044 | ) |
1045 | ); |
1046 | |
1047 | /* Relaxing the maximum boundary to 1.07 (instead of 1.0) |
1048 | * because the last point in the curve must be such that |
1049 | * the maximum display pixel brightness interpolates to |
1050 | * exactly 1.0. The worst case scenario was calculated |
1051 | * around 1.057, so the limit of 1.07 leaves some safety |
1052 | * margin. |
1053 | */ |
1054 | output = dc_fixpt_clamp(output, dc_fixpt_zero, |
1055 | dc_fixpt_from_fraction(107, 100)); |
1056 | |
1057 | rgb->r = output; |
1058 | rgb->g = output; |
1059 | rgb->b = output; |
1060 | } |
1061 | } else { |
1062 | /* Every other clipping after the first |
1063 | * one is dealt with here |
1064 | */ |
1065 | rgb->r = clip; |
1066 | rgb->g = clip; |
1067 | rgb->b = clip; |
1068 | } |
1069 | |
1070 | prv_coord_x = coord_x; |
1071 | ++coord_x; |
1072 | ++rgb; |
1073 | } |
1074 | cal_buffer->buffer_index = -1; |
1075 | |
1076 | return true1; |
1077 | } |
1078 | |
1079 | static bool_Bool build_degamma(struct pwl_float_data_ex *curve, |
1080 | uint32_t hw_points_num, |
1081 | const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type) |
1082 | { |
1083 | uint32_t i; |
1084 | struct gamma_coefficients coeff; |
1085 | uint32_t begin_index, end_index; |
1086 | bool_Bool ret = false0; |
1087 | |
1088 | if (!build_coefficients(&coeff, type)) |
1089 | goto release; |
1090 | |
1091 | i = 0; |
1092 | |
1093 | /* X points is 2^-25 to 2^7 |
1094 | * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions |
1095 | */ |
1096 | begin_index = 13 * NUM_PTS_IN_REGION16; |
1097 | end_index = begin_index + 12 * NUM_PTS_IN_REGION16; |
1098 | |
1099 | while (i != begin_index) { |
1100 | curve[i].r = dc_fixpt_zero; |
1101 | curve[i].g = dc_fixpt_zero; |
1102 | curve[i].b = dc_fixpt_zero; |
1103 | i++; |
1104 | } |
1105 | |
1106 | while (i != end_index) { |
1107 | curve[i].r = translate_to_linear_space_ex( |
1108 | coordinate_x[i].x, &coeff, 0); |
1109 | curve[i].g = curve[i].r; |
1110 | curve[i].b = curve[i].r; |
1111 | i++; |
1112 | } |
1113 | while (i != hw_points_num + 1) { |
1114 | curve[i].r = dc_fixpt_one; |
1115 | curve[i].g = dc_fixpt_one; |
1116 | curve[i].b = dc_fixpt_one; |
1117 | i++; |
1118 | } |
1119 | ret = true1; |
1120 | release: |
1121 | return ret; |
1122 | } |
1123 | |
1124 | |
1125 | |
1126 | |
1127 | |
1128 | static void build_hlg_degamma(struct pwl_float_data_ex *degamma, |
1129 | uint32_t hw_points_num, |
1130 | const struct hw_x_point *coordinate_x, |
1131 | uint32_t sdr_white_level, uint32_t max_luminance_nits) |
1132 | { |
1133 | uint32_t i; |
1134 | |
1135 | struct pwl_float_data_ex *rgb = degamma; |
1136 | const struct hw_x_point *coord_x = coordinate_x; |
1137 | |
1138 | i = 0; |
1139 | // check when i == 434 |
1140 | while (i != hw_points_num + 1) { |
1141 | compute_hlg_eotf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); |
1142 | rgb->g = rgb->r; |
1143 | rgb->b = rgb->r; |
1144 | ++coord_x; |
1145 | ++rgb; |
1146 | ++i; |
1147 | } |
1148 | } |
1149 | |
1150 | |
1151 | static void build_hlg_regamma(struct pwl_float_data_ex *regamma, |
1152 | uint32_t hw_points_num, |
1153 | const struct hw_x_point *coordinate_x, |
1154 | uint32_t sdr_white_level, uint32_t max_luminance_nits) |
1155 | { |
1156 | uint32_t i; |
1157 | |
1158 | struct pwl_float_data_ex *rgb = regamma; |
1159 | const struct hw_x_point *coord_x = coordinate_x; |
1160 | |
1161 | i = 0; |
1162 | |
1163 | // when i == 471 |
1164 | while (i != hw_points_num + 1) { |
1165 | compute_hlg_oetf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); |
1166 | rgb->g = rgb->r; |
1167 | rgb->b = rgb->r; |
1168 | ++coord_x; |
1169 | ++rgb; |
1170 | ++i; |
1171 | } |
1172 | } |
1173 | |
1174 | static void scale_gamma(struct pwl_float_data *pwl_rgb, |
1175 | const struct dc_gamma *ramp, |
1176 | struct dividers dividers) |
1177 | { |
1178 | const struct fixed31_32 max_driver = dc_fixpt_from_int(0xFFFF); |
1179 | const struct fixed31_32 max_os = dc_fixpt_from_int(0xFF00); |
1180 | struct fixed31_32 scaler = max_os; |
1181 | uint32_t i; |
1182 | struct pwl_float_data *rgb = pwl_rgb; |
1183 | struct pwl_float_data *rgb_last = rgb + ramp->num_entries - 1; |
1184 | |
1185 | i = 0; |
1186 | |
1187 | do { |
1188 | if (dc_fixpt_lt(max_os, ramp->entries.red[i]) || |
1189 | dc_fixpt_lt(max_os, ramp->entries.green[i]) || |
1190 | dc_fixpt_lt(max_os, ramp->entries.blue[i])) { |
1191 | scaler = max_driver; |
1192 | break; |
1193 | } |
1194 | ++i; |
1195 | } while (i != ramp->num_entries); |
1196 | |
1197 | i = 0; |
1198 | |
1199 | do { |
1200 | rgb->r = dc_fixpt_div( |
1201 | ramp->entries.red[i], scaler); |
1202 | rgb->g = dc_fixpt_div( |
1203 | ramp->entries.green[i], scaler); |
1204 | rgb->b = dc_fixpt_div( |
1205 | ramp->entries.blue[i], scaler); |
1206 | |
1207 | ++rgb; |
1208 | ++i; |
1209 | } while (i != ramp->num_entries); |
1210 | |
1211 | rgb->r = dc_fixpt_mul(rgb_last->r, |
1212 | dividers.divider1); |
1213 | rgb->g = dc_fixpt_mul(rgb_last->g, |
1214 | dividers.divider1); |
1215 | rgb->b = dc_fixpt_mul(rgb_last->b, |
1216 | dividers.divider1); |
1217 | |
1218 | ++rgb; |
1219 | |
1220 | rgb->r = dc_fixpt_mul(rgb_last->r, |
1221 | dividers.divider2); |
1222 | rgb->g = dc_fixpt_mul(rgb_last->g, |
1223 | dividers.divider2); |
1224 | rgb->b = dc_fixpt_mul(rgb_last->b, |
1225 | dividers.divider2); |
1226 | |
1227 | ++rgb; |
1228 | |
1229 | rgb->r = dc_fixpt_mul(rgb_last->r, |
1230 | dividers.divider3); |
1231 | rgb->g = dc_fixpt_mul(rgb_last->g, |
1232 | dividers.divider3); |
1233 | rgb->b = dc_fixpt_mul(rgb_last->b, |
1234 | dividers.divider3); |
1235 | } |
1236 | |
1237 | static void scale_gamma_dx(struct pwl_float_data *pwl_rgb, |
1238 | const struct dc_gamma *ramp, |
1239 | struct dividers dividers) |
1240 | { |
1241 | uint32_t i; |
1242 | struct fixed31_32 min = dc_fixpt_zero; |
1243 | struct fixed31_32 max = dc_fixpt_one; |
1244 | |
1245 | struct fixed31_32 delta = dc_fixpt_zero; |
1246 | struct fixed31_32 offset = dc_fixpt_zero; |
1247 | |
1248 | for (i = 0 ; i < ramp->num_entries; i++) { |
1249 | if (dc_fixpt_lt(ramp->entries.red[i], min)) |
1250 | min = ramp->entries.red[i]; |
1251 | |
1252 | if (dc_fixpt_lt(ramp->entries.green[i], min)) |
1253 | min = ramp->entries.green[i]; |
1254 | |
1255 | if (dc_fixpt_lt(ramp->entries.blue[i], min)) |
1256 | min = ramp->entries.blue[i]; |
1257 | |
1258 | if (dc_fixpt_lt(max, ramp->entries.red[i])) |
1259 | max = ramp->entries.red[i]; |
1260 | |
1261 | if (dc_fixpt_lt(max, ramp->entries.green[i])) |
1262 | max = ramp->entries.green[i]; |
1263 | |
1264 | if (dc_fixpt_lt(max, ramp->entries.blue[i])) |
1265 | max = ramp->entries.blue[i]; |
1266 | } |
1267 | |
1268 | if (dc_fixpt_lt(min, dc_fixpt_zero)) |
1269 | delta = dc_fixpt_neg(min); |
1270 | |
1271 | offset = dc_fixpt_add(min, max); |
1272 | |
1273 | for (i = 0 ; i < ramp->num_entries; i++) { |
1274 | pwl_rgb[i].r = dc_fixpt_div( |
1275 | dc_fixpt_add( |
1276 | ramp->entries.red[i], delta), offset); |
1277 | pwl_rgb[i].g = dc_fixpt_div( |
1278 | dc_fixpt_add( |
1279 | ramp->entries.green[i], delta), offset); |
1280 | pwl_rgb[i].b = dc_fixpt_div( |
1281 | dc_fixpt_add( |
1282 | ramp->entries.blue[i], delta), offset); |
1283 | |
1284 | } |
1285 | |
1286 | pwl_rgb[i].r = dc_fixpt_sub(dc_fixpt_mul_int( |
1287 | pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r); |
1288 | pwl_rgb[i].g = dc_fixpt_sub(dc_fixpt_mul_int( |
1289 | pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g); |
1290 | pwl_rgb[i].b = dc_fixpt_sub(dc_fixpt_mul_int( |
1291 | pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b); |
1292 | ++i; |
1293 | pwl_rgb[i].r = dc_fixpt_sub(dc_fixpt_mul_int( |
1294 | pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r); |
1295 | pwl_rgb[i].g = dc_fixpt_sub(dc_fixpt_mul_int( |
1296 | pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g); |
1297 | pwl_rgb[i].b = dc_fixpt_sub(dc_fixpt_mul_int( |
1298 | pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b); |
1299 | } |
1300 | |
1301 | /* todo: all these scale_gamma functions are inherently the same but |
1302 | * take different structures as params or different format for ramp |
1303 | * values. We could probably implement it in a more generic fashion |
1304 | */ |
1305 | static void scale_user_regamma_ramp(struct pwl_float_data *pwl_rgb, |
1306 | const struct regamma_ramp *ramp, |
1307 | struct dividers dividers) |
1308 | { |
1309 | unsigned short max_driver = 0xFFFF; |
1310 | unsigned short max_os = 0xFF00; |
1311 | unsigned short scaler = max_os; |
1312 | uint32_t i; |
1313 | struct pwl_float_data *rgb = pwl_rgb; |
1314 | struct pwl_float_data *rgb_last = rgb + GAMMA_RGB_256_ENTRIES - 1; |
1315 | |
1316 | i = 0; |
1317 | do { |
1318 | if (ramp->gamma[i] > max_os || |
1319 | ramp->gamma[i + 256] > max_os || |
1320 | ramp->gamma[i + 512] > max_os) { |
1321 | scaler = max_driver; |
1322 | break; |
1323 | } |
1324 | i++; |
1325 | } while (i != GAMMA_RGB_256_ENTRIES); |
1326 | |
1327 | i = 0; |
1328 | do { |
1329 | rgb->r = dc_fixpt_from_fraction( |
1330 | ramp->gamma[i], scaler); |
1331 | rgb->g = dc_fixpt_from_fraction( |
1332 | ramp->gamma[i + 256], scaler); |
1333 | rgb->b = dc_fixpt_from_fraction( |
1334 | ramp->gamma[i + 512], scaler); |
1335 | |
1336 | ++rgb; |
1337 | ++i; |
1338 | } while (i != GAMMA_RGB_256_ENTRIES); |
1339 | |
1340 | rgb->r = dc_fixpt_mul(rgb_last->r, |
1341 | dividers.divider1); |
1342 | rgb->g = dc_fixpt_mul(rgb_last->g, |
1343 | dividers.divider1); |
1344 | rgb->b = dc_fixpt_mul(rgb_last->b, |
1345 | dividers.divider1); |
1346 | |
1347 | ++rgb; |
1348 | |
1349 | rgb->r = dc_fixpt_mul(rgb_last->r, |
1350 | dividers.divider2); |
1351 | rgb->g = dc_fixpt_mul(rgb_last->g, |
1352 | dividers.divider2); |
1353 | rgb->b = dc_fixpt_mul(rgb_last->b, |
1354 | dividers.divider2); |
1355 | |
1356 | ++rgb; |
1357 | |
1358 | rgb->r = dc_fixpt_mul(rgb_last->r, |
1359 | dividers.divider3); |
1360 | rgb->g = dc_fixpt_mul(rgb_last->g, |
1361 | dividers.divider3); |
1362 | rgb->b = dc_fixpt_mul(rgb_last->b, |
1363 | dividers.divider3); |
1364 | } |
1365 | |
1366 | /* |
1367 | * RS3+ color transform DDI - 1D LUT adjustment is composed with regamma here |
1368 | * Input is evenly distributed in the output color space as specified in |
1369 | * SetTimings |
1370 | * |
1371 | * Interpolation details: |
1372 | * 1D LUT has 4096 values which give curve correction in 0-1 float range |
1373 | * for evenly spaced points in 0-1 range. lut1D[index] gives correction |
1374 | * for index/4095. |
1375 | * First we find index for which: |
1376 | * index/4095 < regamma_y < (index+1)/4095 => |
1377 | * index < 4095*regamma_y < index + 1 |
1378 | * norm_y = 4095*regamma_y, and index is just truncating to nearest integer |
1379 | * lut1 = lut1D[index], lut2 = lut1D[index+1] |
1380 | * |
1381 | * adjustedY is then linearly interpolating regamma Y between lut1 and lut2 |
1382 | * |
1383 | * Custom degamma on Linux uses the same interpolation math, so is handled here |
1384 | */ |
1385 | static void apply_lut_1d( |
1386 | const struct dc_gamma *ramp, |
1387 | uint32_t num_hw_points, |
1388 | struct dc_transfer_func_distributed_points *tf_pts) |
1389 | { |
1390 | int i = 0; |
1391 | int color = 0; |
1392 | struct fixed31_32 *regamma_y; |
1393 | struct fixed31_32 norm_y; |
1394 | struct fixed31_32 lut1; |
1395 | struct fixed31_32 lut2; |
1396 | const int max_lut_index = 4095; |
1397 | const struct fixed31_32 penult_lut_index_f = |
1398 | dc_fixpt_from_int(max_lut_index-1); |
1399 | const struct fixed31_32 max_lut_index_f = |
1400 | dc_fixpt_from_int(max_lut_index); |
1401 | int32_t index = 0, index_next = 0; |
1402 | struct fixed31_32 index_f; |
1403 | struct fixed31_32 delta_lut; |
1404 | struct fixed31_32 delta_index; |
1405 | |
1406 | if (ramp->type != GAMMA_CS_TFM_1D && ramp->type != GAMMA_CUSTOM) |
1407 | return; // this is not expected |
1408 | |
1409 | for (i = 0; i < num_hw_points; i++) { |
1410 | for (color = 0; color < 3; color++) { |
1411 | if (color == 0) |
1412 | regamma_y = &tf_pts->red[i]; |
1413 | else if (color == 1) |
1414 | regamma_y = &tf_pts->green[i]; |
1415 | else |
1416 | regamma_y = &tf_pts->blue[i]; |
1417 | |
1418 | norm_y = dc_fixpt_mul(max_lut_index_f, |
1419 | *regamma_y); |
1420 | index = dc_fixpt_floor(norm_y); |
1421 | index_f = dc_fixpt_from_int(index); |
1422 | |
1423 | if (index < 0) |
1424 | continue; |
1425 | |
1426 | if (index <= max_lut_index) |
1427 | index_next = (index == max_lut_index) ? index : index+1; |
1428 | else { |
1429 | /* Here we are dealing with the last point in the curve, |
1430 | * which in some cases might exceed the range given by |
1431 | * max_lut_index. So we interpolate the value using |
1432 | * max_lut_index and max_lut_index - 1. |
1433 | */ |
1434 | index = max_lut_index - 1; |
1435 | index_next = max_lut_index; |
1436 | index_f = penult_lut_index_f; |
1437 | } |
1438 | |
1439 | if (color == 0) { |
1440 | lut1 = ramp->entries.red[index]; |
1441 | lut2 = ramp->entries.red[index_next]; |
1442 | } else if (color == 1) { |
1443 | lut1 = ramp->entries.green[index]; |
1444 | lut2 = ramp->entries.green[index_next]; |
1445 | } else { |
1446 | lut1 = ramp->entries.blue[index]; |
1447 | lut2 = ramp->entries.blue[index_next]; |
1448 | } |
1449 | |
1450 | // we have everything now, so interpolate |
1451 | delta_lut = dc_fixpt_sub(lut2, lut1); |
1452 | delta_index = dc_fixpt_sub(norm_y, index_f); |
1453 | |
1454 | *regamma_y = dc_fixpt_add(lut1, |
1455 | dc_fixpt_mul(delta_index, delta_lut)); |
1456 | } |
1457 | } |
1458 | } |
1459 | |
1460 | static void build_evenly_distributed_points( |
1461 | struct gamma_pixel *points, |
1462 | uint32_t numberof_points, |
1463 | struct dividers dividers) |
1464 | { |
1465 | struct gamma_pixel *p = points; |
1466 | struct gamma_pixel *p_last; |
1467 | |
1468 | uint32_t i = 0; |
1469 | |
1470 | // This function should not gets called with 0 as a parameter |
1471 | ASSERT(numberof_points > 0)do { if (({ static int __warned; int __ret = !!(!(numberof_points > 0)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(numberof_points > 0)", "/usr/src/sys/dev/pci/drm/amd/display/modules/color/color_gamma.c" , 1471); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
1472 | p_last = p + numberof_points - 1; |
1473 | |
1474 | do { |
1475 | struct fixed31_32 value = dc_fixpt_from_fraction(i, |
1476 | numberof_points - 1); |
1477 | |
1478 | p->r = value; |
1479 | p->g = value; |
1480 | p->b = value; |
1481 | |
1482 | ++p; |
1483 | ++i; |
1484 | } while (i < numberof_points); |
1485 | |
1486 | p->r = dc_fixpt_div(p_last->r, dividers.divider1); |
1487 | p->g = dc_fixpt_div(p_last->g, dividers.divider1); |
1488 | p->b = dc_fixpt_div(p_last->b, dividers.divider1); |
1489 | |
1490 | ++p; |
1491 | |
1492 | p->r = dc_fixpt_div(p_last->r, dividers.divider2); |
1493 | p->g = dc_fixpt_div(p_last->g, dividers.divider2); |
1494 | p->b = dc_fixpt_div(p_last->b, dividers.divider2); |
1495 | |
1496 | ++p; |
1497 | |
1498 | p->r = dc_fixpt_div(p_last->r, dividers.divider3); |
1499 | p->g = dc_fixpt_div(p_last->g, dividers.divider3); |
1500 | p->b = dc_fixpt_div(p_last->b, dividers.divider3); |
1501 | } |
1502 | |
1503 | static inline void copy_rgb_regamma_to_coordinates_x( |
1504 | struct hw_x_point *coordinates_x, |
1505 | uint32_t hw_points_num, |
1506 | const struct pwl_float_data_ex *rgb_ex) |
1507 | { |
1508 | struct hw_x_point *coords = coordinates_x; |
1509 | uint32_t i = 0; |
1510 | const struct pwl_float_data_ex *rgb_regamma = rgb_ex; |
1511 | |
1512 | while (i <= hw_points_num + 1) { |
1513 | coords->regamma_y_red = rgb_regamma->r; |
1514 | coords->regamma_y_green = rgb_regamma->g; |
1515 | coords->regamma_y_blue = rgb_regamma->b; |
1516 | |
1517 | ++coords; |
1518 | ++rgb_regamma; |
1519 | ++i; |
1520 | } |
1521 | } |
1522 | |
1523 | static bool_Bool calculate_interpolated_hardware_curve( |
1524 | const struct dc_gamma *ramp, |
1525 | struct pixel_gamma_point *coeff128, |
1526 | struct pwl_float_data *rgb_user, |
1527 | const struct hw_x_point *coordinates_x, |
1528 | const struct gamma_pixel *axis_x, |
1529 | uint32_t number_of_points, |
1530 | struct dc_transfer_func_distributed_points *tf_pts) |
1531 | { |
1532 | |
1533 | const struct pixel_gamma_point *coeff = coeff128; |
1534 | uint32_t max_entries = 3 - 1; |
1535 | |
1536 | uint32_t i = 0; |
1537 | |
1538 | for (i = 0; i < 3; i++) { |
1539 | if (!build_custom_gamma_mapping_coefficients_worker( |
1540 | ramp, coeff128, coordinates_x, axis_x, i, |
1541 | number_of_points)) |
1542 | return false0; |
1543 | } |
1544 | |
1545 | i = 0; |
1546 | max_entries += ramp->num_entries; |
1547 | |
1548 | /* TODO: float point case */ |
1549 | |
1550 | while (i <= number_of_points) { |
1551 | tf_pts->red[i] = calculate_mapped_value( |
1552 | rgb_user, coeff, CHANNEL_NAME_RED, max_entries); |
1553 | tf_pts->green[i] = calculate_mapped_value( |
1554 | rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries); |
1555 | tf_pts->blue[i] = calculate_mapped_value( |
1556 | rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries); |
1557 | |
1558 | ++coeff; |
1559 | ++i; |
1560 | } |
1561 | |
1562 | return true1; |
1563 | } |
1564 | |
1565 | /* The "old" interpolation uses a complicated scheme to build an array of |
1566 | * coefficients while also using an array of 0-255 normalized to 0-1 |
1567 | * Then there's another loop using both of the above + new scaled user ramp |
1568 | * and we concatenate them. It also searches for points of interpolation and |
1569 | * uses enums for positions. |
1570 | * |
1571 | * This function uses a different approach: |
1572 | * user ramp is always applied on X with 0/255, 1/255, 2/255, ..., 255/255 |
1573 | * To find index for hwX , we notice the following: |
1574 | * i/255 <= hwX < (i+1)/255 <=> i <= 255*hwX < i+1 |
1575 | * See apply_lut_1d which is the same principle, but on 4K entry 1D LUT |
1576 | * |
1577 | * Once the index is known, combined Y is simply: |
1578 | * user_ramp(index) + (hwX-index/255)*(user_ramp(index+1) - user_ramp(index) |
1579 | * |
1580 | * We should switch to this method in all cases, it's simpler and faster |
1581 | * ToDo one day - for now this only applies to ADL regamma to avoid regression |
1582 | * for regular use cases (sRGB and PQ) |
1583 | */ |
1584 | static void interpolate_user_regamma(uint32_t hw_points_num, |
1585 | struct pwl_float_data *rgb_user, |
1586 | bool_Bool apply_degamma, |
1587 | struct dc_transfer_func_distributed_points *tf_pts) |
1588 | { |
1589 | uint32_t i; |
1590 | uint32_t color = 0; |
1591 | int32_t index; |
1592 | int32_t index_next; |
1593 | struct fixed31_32 *tf_point; |
1594 | struct fixed31_32 hw_x; |
1595 | struct fixed31_32 norm_factor = |
1596 | dc_fixpt_from_int(255); |
1597 | struct fixed31_32 norm_x; |
1598 | struct fixed31_32 index_f; |
1599 | struct fixed31_32 lut1; |
1600 | struct fixed31_32 lut2; |
1601 | struct fixed31_32 delta_lut; |
1602 | struct fixed31_32 delta_index; |
1603 | const struct fixed31_32 one = dc_fixpt_from_int(1); |
1604 | |
1605 | i = 0; |
1606 | /* fixed_pt library has problems handling too small values */ |
1607 | while (i != 32) { |
1608 | tf_pts->red[i] = dc_fixpt_zero; |
1609 | tf_pts->green[i] = dc_fixpt_zero; |
1610 | tf_pts->blue[i] = dc_fixpt_zero; |
1611 | ++i; |
1612 | } |
1613 | while (i <= hw_points_num + 1) { |
1614 | for (color = 0; color < 3; color++) { |
1615 | if (color == 0) |
1616 | tf_point = &tf_pts->red[i]; |
1617 | else if (color == 1) |
1618 | tf_point = &tf_pts->green[i]; |
1619 | else |
1620 | tf_point = &tf_pts->blue[i]; |
1621 | |
1622 | if (apply_degamma) { |
1623 | if (color == 0) |
1624 | hw_x = coordinates_x[i].regamma_y_red; |
1625 | else if (color == 1) |
1626 | hw_x = coordinates_x[i].regamma_y_green; |
1627 | else |
1628 | hw_x = coordinates_x[i].regamma_y_blue; |
1629 | } else |
1630 | hw_x = coordinates_x[i].x; |
1631 | |
1632 | if (dc_fixpt_le(one, hw_x)) |
1633 | hw_x = one; |
1634 | |
1635 | norm_x = dc_fixpt_mul(norm_factor, hw_x); |
1636 | index = dc_fixpt_floor(norm_x); |
1637 | if (index < 0 || index > 255) |
1638 | continue; |
1639 | |
1640 | index_f = dc_fixpt_from_int(index); |
1641 | index_next = (index == 255) ? index : index + 1; |
1642 | |
1643 | if (color == 0) { |
1644 | lut1 = rgb_user[index].r; |
1645 | lut2 = rgb_user[index_next].r; |
1646 | } else if (color == 1) { |
1647 | lut1 = rgb_user[index].g; |
1648 | lut2 = rgb_user[index_next].g; |
1649 | } else { |
1650 | lut1 = rgb_user[index].b; |
1651 | lut2 = rgb_user[index_next].b; |
1652 | } |
1653 | |
1654 | // we have everything now, so interpolate |
1655 | delta_lut = dc_fixpt_sub(lut2, lut1); |
1656 | delta_index = dc_fixpt_sub(norm_x, index_f); |
1657 | |
1658 | *tf_point = dc_fixpt_add(lut1, |
1659 | dc_fixpt_mul(delta_index, delta_lut)); |
1660 | } |
1661 | ++i; |
1662 | } |
1663 | } |
1664 | |
1665 | static void build_new_custom_resulted_curve( |
1666 | uint32_t hw_points_num, |
1667 | struct dc_transfer_func_distributed_points *tf_pts) |
1668 | { |
1669 | uint32_t i = 0; |
1670 | |
1671 | while (i != hw_points_num + 1) { |
1672 | tf_pts->red[i] = dc_fixpt_clamp( |
1673 | tf_pts->red[i], dc_fixpt_zero, |
1674 | dc_fixpt_one); |
1675 | tf_pts->green[i] = dc_fixpt_clamp( |
1676 | tf_pts->green[i], dc_fixpt_zero, |
1677 | dc_fixpt_one); |
1678 | tf_pts->blue[i] = dc_fixpt_clamp( |
1679 | tf_pts->blue[i], dc_fixpt_zero, |
1680 | dc_fixpt_one); |
1681 | |
1682 | ++i; |
1683 | } |
1684 | } |
1685 | |
1686 | static void apply_degamma_for_user_regamma(struct pwl_float_data_ex *rgb_regamma, |
1687 | uint32_t hw_points_num, struct calculate_buffer *cal_buffer) |
1688 | { |
1689 | uint32_t i; |
1690 | |
1691 | struct gamma_coefficients coeff; |
1692 | struct pwl_float_data_ex *rgb = rgb_regamma; |
1693 | const struct hw_x_point *coord_x = coordinates_x; |
1694 | |
1695 | build_coefficients(&coeff, TRANSFER_FUNCTION_SRGB); |
1696 | |
1697 | i = 0; |
1698 | while (i != hw_points_num + 1) { |
1699 | rgb->r = translate_from_linear_space_ex( |
1700 | coord_x->x, &coeff, 0, cal_buffer); |
1701 | rgb->g = rgb->r; |
1702 | rgb->b = rgb->r; |
1703 | ++coord_x; |
1704 | ++rgb; |
1705 | ++i; |
1706 | } |
1707 | } |
1708 | |
1709 | static bool_Bool map_regamma_hw_to_x_user( |
1710 | const struct dc_gamma *ramp, |
1711 | struct pixel_gamma_point *coeff128, |
1712 | struct pwl_float_data *rgb_user, |
1713 | struct hw_x_point *coords_x, |
1714 | const struct gamma_pixel *axis_x, |
1715 | const struct pwl_float_data_ex *rgb_regamma, |
1716 | uint32_t hw_points_num, |
1717 | struct dc_transfer_func_distributed_points *tf_pts, |
1718 | bool_Bool mapUserRamp, |
1719 | bool_Bool doClamping) |
1720 | { |
1721 | /* setup to spare calculated ideal regamma values */ |
1722 | |
1723 | int i = 0; |
1724 | struct hw_x_point *coords = coords_x; |
1725 | const struct pwl_float_data_ex *regamma = rgb_regamma; |
1726 | |
1727 | if (ramp && mapUserRamp) { |
1728 | copy_rgb_regamma_to_coordinates_x(coords, |
1729 | hw_points_num, |
1730 | rgb_regamma); |
1731 | |
1732 | calculate_interpolated_hardware_curve( |
1733 | ramp, coeff128, rgb_user, coords, axis_x, |
1734 | hw_points_num, tf_pts); |
1735 | } else { |
1736 | /* just copy current rgb_regamma into tf_pts */ |
1737 | while (i <= hw_points_num) { |
1738 | tf_pts->red[i] = regamma->r; |
1739 | tf_pts->green[i] = regamma->g; |
1740 | tf_pts->blue[i] = regamma->b; |
1741 | |
1742 | ++regamma; |
1743 | ++i; |
1744 | } |
1745 | } |
1746 | |
1747 | if (doClamping) { |
1748 | /* this should be named differently, all it does is clamp to 0-1 */ |
1749 | build_new_custom_resulted_curve(hw_points_num, tf_pts); |
1750 | } |
1751 | |
1752 | return true1; |
1753 | } |
1754 | |
1755 | #define _EXTRA_POINTS3 3 |
1756 | |
1757 | bool_Bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, |
1758 | const struct regamma_lut *regamma, |
1759 | struct calculate_buffer *cal_buffer, |
1760 | const struct dc_gamma *ramp) |
1761 | { |
1762 | struct gamma_coefficients coeff; |
1763 | const struct hw_x_point *coord_x = coordinates_x; |
1764 | uint32_t i = 0; |
1765 | |
1766 | do { |
1767 | coeff.a0[i] = dc_fixpt_from_fraction( |
1768 | regamma->coeff.A0[i], 10000000); |
1769 | coeff.a1[i] = dc_fixpt_from_fraction( |
1770 | regamma->coeff.A1[i], 1000); |
1771 | coeff.a2[i] = dc_fixpt_from_fraction( |
1772 | regamma->coeff.A2[i], 1000); |
1773 | coeff.a3[i] = dc_fixpt_from_fraction( |
1774 | regamma->coeff.A3[i], 1000); |
1775 | coeff.user_gamma[i] = dc_fixpt_from_fraction( |
1776 | regamma->coeff.gamma[i], 1000); |
1777 | |
1778 | ++i; |
1779 | } while (i != 3); |
1780 | |
1781 | i = 0; |
1782 | /* fixed_pt library has problems handling too small values */ |
1783 | while (i != 32) { |
1784 | output_tf->tf_pts.red[i] = dc_fixpt_zero; |
1785 | output_tf->tf_pts.green[i] = dc_fixpt_zero; |
1786 | output_tf->tf_pts.blue[i] = dc_fixpt_zero; |
1787 | ++coord_x; |
1788 | ++i; |
1789 | } |
1790 | while (i != MAX_HW_POINTS(16*32) + 1) { |
1791 | output_tf->tf_pts.red[i] = translate_from_linear_space_ex( |
1792 | coord_x->x, &coeff, 0, cal_buffer); |
1793 | output_tf->tf_pts.green[i] = translate_from_linear_space_ex( |
1794 | coord_x->x, &coeff, 1, cal_buffer); |
1795 | output_tf->tf_pts.blue[i] = translate_from_linear_space_ex( |
1796 | coord_x->x, &coeff, 2, cal_buffer); |
1797 | ++coord_x; |
1798 | ++i; |
1799 | } |
1800 | |
1801 | if (ramp && ramp->type == GAMMA_CS_TFM_1D) |
1802 | apply_lut_1d(ramp, MAX_HW_POINTS(16*32), &output_tf->tf_pts); |
1803 | |
1804 | // this function just clamps output to 0-1 |
1805 | build_new_custom_resulted_curve(MAX_HW_POINTS(16*32), &output_tf->tf_pts); |
1806 | output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; |
1807 | |
1808 | return true1; |
1809 | } |
1810 | |
1811 | bool_Bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf, |
1812 | const struct regamma_lut *regamma, |
1813 | struct calculate_buffer *cal_buffer, |
1814 | const struct dc_gamma *ramp) |
1815 | { |
1816 | struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; |
1817 | struct dividers dividers; |
1818 | |
1819 | struct pwl_float_data *rgb_user = NULL((void *)0); |
1820 | struct pwl_float_data_ex *rgb_regamma = NULL((void *)0); |
1821 | bool_Bool ret = false0; |
1822 | |
1823 | if (regamma == NULL((void *)0)) |
1824 | return false0; |
1825 | |
1826 | output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; |
1827 | |
1828 | rgb_user = kcalloc(GAMMA_RGB_256_ENTRIES + _EXTRA_POINTS3, |
1829 | sizeof(*rgb_user), |
1830 | GFP_KERNEL(0x0001 | 0x0004)); |
1831 | if (!rgb_user) |
1832 | goto rgb_user_alloc_fail; |
1833 | |
1834 | rgb_regamma = kcalloc(MAX_HW_POINTS(16*32) + _EXTRA_POINTS3, |
1835 | sizeof(*rgb_regamma), |
1836 | GFP_KERNEL(0x0001 | 0x0004)); |
1837 | if (!rgb_regamma) |
1838 | goto rgb_regamma_alloc_fail; |
1839 | |
1840 | dividers.divider1 = dc_fixpt_from_fraction(3, 2); |
1841 | dividers.divider2 = dc_fixpt_from_int(2); |
1842 | dividers.divider3 = dc_fixpt_from_fraction(5, 2); |
1843 | |
1844 | scale_user_regamma_ramp(rgb_user, ®amma->ramp, dividers); |
1845 | |
1846 | if (regamma->flags.bits.applyDegamma == 1) { |
1847 | apply_degamma_for_user_regamma(rgb_regamma, MAX_HW_POINTS(16*32), cal_buffer); |
1848 | copy_rgb_regamma_to_coordinates_x(coordinates_x, |
1849 | MAX_HW_POINTS(16*32), rgb_regamma); |
1850 | } |
1851 | |
1852 | interpolate_user_regamma(MAX_HW_POINTS(16*32), rgb_user, |
1853 | regamma->flags.bits.applyDegamma, tf_pts); |
1854 | |
1855 | // no custom HDR curves! |
1856 | tf_pts->end_exponent = 0; |
1857 | tf_pts->x_point_at_y1_red = 1; |
1858 | tf_pts->x_point_at_y1_green = 1; |
1859 | tf_pts->x_point_at_y1_blue = 1; |
1860 | |
1861 | if (ramp && ramp->type == GAMMA_CS_TFM_1D) |
1862 | apply_lut_1d(ramp, MAX_HW_POINTS(16*32), &output_tf->tf_pts); |
1863 | |
1864 | // this function just clamps output to 0-1 |
1865 | build_new_custom_resulted_curve(MAX_HW_POINTS(16*32), tf_pts); |
1866 | |
1867 | ret = true1; |
1868 | |
1869 | kfree(rgb_regamma); |
1870 | rgb_regamma_alloc_fail: |
1871 | kfree(rgb_user); |
1872 | rgb_user_alloc_fail: |
1873 | return ret; |
1874 | } |
1875 | |
1876 | bool_Bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps, |
1877 | struct dc_transfer_func *input_tf, |
1878 | const struct dc_gamma *ramp, bool_Bool mapUserRamp) |
1879 | { |
1880 | struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts; |
1881 | struct dividers dividers; |
1882 | struct pwl_float_data *rgb_user = NULL((void *)0); |
1883 | struct pwl_float_data_ex *curve = NULL((void *)0); |
1884 | struct gamma_pixel *axis_x = NULL((void *)0); |
1885 | struct pixel_gamma_point *coeff = NULL((void *)0); |
1886 | enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; |
1887 | uint32_t i; |
1888 | bool_Bool ret = false0; |
1889 | |
1890 | if (input_tf->type == TF_TYPE_BYPASS) |
1891 | return false0; |
1892 | |
1893 | /* we can use hardcoded curve for plain SRGB TF |
1894 | * If linear, it's bypass if on user ramp |
1895 | */ |
1896 | if (input_tf->type == TF_TYPE_PREDEFINED) { |
1897 | if ((input_tf->tf == TRANSFER_FUNCTION_SRGB || |
1898 | input_tf->tf == TRANSFER_FUNCTION_LINEAR) && |
1899 | !mapUserRamp) |
1900 | return true1; |
1901 | |
1902 | if (dc_caps != NULL((void *)0) && |
1903 | dc_caps->dpp.dcn_arch == 1) { |
1904 | |
1905 | if (input_tf->tf == TRANSFER_FUNCTION_PQ && |
1906 | dc_caps->dpp.dgam_rom_caps.pq == 1) |
1907 | return true1; |
1908 | |
1909 | if (input_tf->tf == TRANSFER_FUNCTION_GAMMA22 && |
1910 | dc_caps->dpp.dgam_rom_caps.gamma2_2 == 1) |
1911 | return true1; |
1912 | |
1913 | // HLG OOTF not accounted for |
1914 | if (input_tf->tf == TRANSFER_FUNCTION_HLG && |
1915 | dc_caps->dpp.dgam_rom_caps.hlg == 1) |
1916 | return true1; |
1917 | } |
1918 | } |
1919 | |
1920 | input_tf->type = TF_TYPE_DISTRIBUTED_POINTS; |
1921 | |
1922 | if (mapUserRamp && ramp && ramp->type == GAMMA_RGB_256) { |
1923 | rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS3, |
1924 | sizeof(*rgb_user), |
1925 | GFP_KERNEL(0x0001 | 0x0004)); |
1926 | if (!rgb_user) |
1927 | goto rgb_user_alloc_fail; |
1928 | |
1929 | axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS3, sizeof(*axis_x), |
1930 | GFP_KERNEL(0x0001 | 0x0004)); |
1931 | if (!axis_x) |
1932 | goto axis_x_alloc_fail; |
1933 | |
1934 | dividers.divider1 = dc_fixpt_from_fraction(3, 2); |
1935 | dividers.divider2 = dc_fixpt_from_int(2); |
1936 | dividers.divider3 = dc_fixpt_from_fraction(5, 2); |
1937 | |
1938 | build_evenly_distributed_points( |
1939 | axis_x, |
1940 | ramp->num_entries, |
1941 | dividers); |
1942 | |
1943 | scale_gamma(rgb_user, ramp, dividers); |
1944 | } |
1945 | |
1946 | curve = kvcalloc(MAX_HW_POINTS(16*32) + _EXTRA_POINTS3, sizeof(*curve), |
1947 | GFP_KERNEL(0x0001 | 0x0004)); |
1948 | if (!curve) |
1949 | goto curve_alloc_fail; |
1950 | |
1951 | coeff = kvcalloc(MAX_HW_POINTS(16*32) + _EXTRA_POINTS3, sizeof(*coeff), |
1952 | GFP_KERNEL(0x0001 | 0x0004)); |
1953 | if (!coeff) |
1954 | goto coeff_alloc_fail; |
1955 | |
1956 | tf = input_tf->tf; |
1957 | |
1958 | if (tf == TRANSFER_FUNCTION_PQ) |
1959 | build_de_pq(curve, |
1960 | MAX_HW_POINTS(16*32), |
1961 | coordinates_x); |
1962 | else if (tf == TRANSFER_FUNCTION_SRGB || |
1963 | tf == TRANSFER_FUNCTION_BT709 || |
1964 | tf == TRANSFER_FUNCTION_GAMMA22 || |
1965 | tf == TRANSFER_FUNCTION_GAMMA24 || |
1966 | tf == TRANSFER_FUNCTION_GAMMA26) |
1967 | build_degamma(curve, |
1968 | MAX_HW_POINTS(16*32), |
1969 | coordinates_x, |
1970 | tf); |
1971 | else if (tf == TRANSFER_FUNCTION_HLG) |
1972 | build_hlg_degamma(curve, |
1973 | MAX_HW_POINTS(16*32), |
1974 | coordinates_x, |
1975 | 80, 1000); |
1976 | else if (tf == TRANSFER_FUNCTION_LINEAR) { |
1977 | // just copy coordinates_x into curve |
1978 | i = 0; |
1979 | while (i != MAX_HW_POINTS(16*32) + 1) { |
1980 | curve[i].r = coordinates_x[i].x; |
1981 | curve[i].g = curve[i].r; |
1982 | curve[i].b = curve[i].r; |
1983 | i++; |
1984 | } |
1985 | } else |
1986 | goto invalid_tf_fail; |
1987 | |
1988 | tf_pts->end_exponent = 0; |
1989 | tf_pts->x_point_at_y1_red = 1; |
1990 | tf_pts->x_point_at_y1_green = 1; |
1991 | tf_pts->x_point_at_y1_blue = 1; |
1992 | |
1993 | if (input_tf->tf == TRANSFER_FUNCTION_PQ) { |
1994 | /* just copy current rgb_regamma into tf_pts */ |
1995 | struct pwl_float_data_ex *curvePt = curve; |
1996 | int i = 0; |
1997 | |
1998 | while (i <= MAX_HW_POINTS(16*32)) { |
1999 | tf_pts->red[i] = curvePt->r; |
2000 | tf_pts->green[i] = curvePt->g; |
2001 | tf_pts->blue[i] = curvePt->b; |
2002 | ++curvePt; |
2003 | ++i; |
2004 | } |
2005 | } else { |
2006 | // clamps to 0-1 |
2007 | map_regamma_hw_to_x_user(ramp, coeff, rgb_user, |
2008 | coordinates_x, axis_x, curve, |
2009 | MAX_HW_POINTS(16*32), tf_pts, |
2010 | mapUserRamp && ramp && ramp->type == GAMMA_RGB_256, |
2011 | true1); |
2012 | } |
2013 | |
2014 | |
2015 | |
2016 | if (ramp && ramp->type == GAMMA_CUSTOM) |
2017 | apply_lut_1d(ramp, MAX_HW_POINTS(16*32), tf_pts); |
2018 | |
2019 | ret = true1; |
2020 | |
2021 | invalid_tf_fail: |
2022 | kvfree(coeff); |
2023 | coeff_alloc_fail: |
2024 | kvfree(curve); |
2025 | curve_alloc_fail: |
2026 | kvfree(axis_x); |
2027 | axis_x_alloc_fail: |
2028 | kvfree(rgb_user); |
2029 | rgb_user_alloc_fail: |
2030 | |
2031 | return ret; |
2032 | } |
2033 | |
2034 | static bool_Bool calculate_curve(enum dc_transfer_func_predefined trans, |
2035 | struct dc_transfer_func_distributed_points *points, |
2036 | struct pwl_float_data_ex *rgb_regamma, |
2037 | const struct hdr_tm_params *fs_params, |
2038 | uint32_t sdr_ref_white_level, |
2039 | struct calculate_buffer *cal_buffer) |
2040 | { |
2041 | uint32_t i; |
2042 | bool_Bool ret = false0; |
2043 | |
2044 | if (trans == TRANSFER_FUNCTION_UNITY || |
2045 | trans == TRANSFER_FUNCTION_LINEAR) { |
2046 | points->end_exponent = 0; |
2047 | points->x_point_at_y1_red = 1; |
2048 | points->x_point_at_y1_green = 1; |
2049 | points->x_point_at_y1_blue = 1; |
2050 | |
2051 | for (i = 0; i <= MAX_HW_POINTS(16*32) ; i++) { |
2052 | rgb_regamma[i].r = coordinates_x[i].x; |
2053 | rgb_regamma[i].g = coordinates_x[i].x; |
2054 | rgb_regamma[i].b = coordinates_x[i].x; |
2055 | } |
2056 | |
2057 | ret = true1; |
2058 | } else if (trans == TRANSFER_FUNCTION_PQ) { |
2059 | points->end_exponent = 7; |
2060 | points->x_point_at_y1_red = 125; |
2061 | points->x_point_at_y1_green = 125; |
2062 | points->x_point_at_y1_blue = 125; |
2063 | |
2064 | build_pq(rgb_regamma, |
2065 | MAX_HW_POINTS(16*32), |
2066 | coordinates_x, |
2067 | sdr_ref_white_level); |
2068 | |
2069 | ret = true1; |
2070 | } else if (trans == TRANSFER_FUNCTION_GAMMA22 && |
2071 | fs_params != NULL((void *)0) && fs_params->skip_tm == 0) { |
2072 | build_freesync_hdr(rgb_regamma, |
2073 | MAX_HW_POINTS(16*32), |
2074 | coordinates_x, |
2075 | fs_params, |
2076 | cal_buffer); |
2077 | |
2078 | ret = true1; |
2079 | } else if (trans == TRANSFER_FUNCTION_HLG) { |
2080 | points->end_exponent = 4; |
2081 | points->x_point_at_y1_red = 12; |
2082 | points->x_point_at_y1_green = 12; |
2083 | points->x_point_at_y1_blue = 12; |
2084 | |
2085 | build_hlg_regamma(rgb_regamma, |
2086 | MAX_HW_POINTS(16*32), |
2087 | coordinates_x, |
2088 | 80, 1000); |
2089 | |
2090 | ret = true1; |
2091 | } else { |
2092 | // trans == TRANSFER_FUNCTION_SRGB |
2093 | // trans == TRANSFER_FUNCTION_BT709 |
2094 | // trans == TRANSFER_FUNCTION_GAMMA22 |
2095 | // trans == TRANSFER_FUNCTION_GAMMA24 |
2096 | // trans == TRANSFER_FUNCTION_GAMMA26 |
2097 | points->end_exponent = 0; |
2098 | points->x_point_at_y1_red = 1; |
2099 | points->x_point_at_y1_green = 1; |
2100 | points->x_point_at_y1_blue = 1; |
2101 | |
2102 | build_regamma(rgb_regamma, |
2103 | MAX_HW_POINTS(16*32), |
2104 | coordinates_x, |
2105 | trans, |
2106 | cal_buffer); |
2107 | |
2108 | ret = true1; |
2109 | } |
2110 | |
2111 | return ret; |
2112 | } |
2113 | |
2114 | bool_Bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, |
2115 | const struct dc_gamma *ramp, bool_Bool mapUserRamp, bool_Bool canRomBeUsed, |
2116 | const struct hdr_tm_params *fs_params, |
2117 | struct calculate_buffer *cal_buffer) |
2118 | { |
2119 | struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; |
2120 | struct dividers dividers; |
2121 | |
2122 | struct pwl_float_data *rgb_user = NULL((void *)0); |
2123 | struct pwl_float_data_ex *rgb_regamma = NULL((void *)0); |
2124 | struct gamma_pixel *axis_x = NULL((void *)0); |
2125 | struct pixel_gamma_point *coeff = NULL((void *)0); |
2126 | enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; |
2127 | bool_Bool doClamping = true1; |
2128 | bool_Bool ret = false0; |
2129 | |
2130 | if (output_tf->type == TF_TYPE_BYPASS) |
2131 | return false0; |
2132 | |
2133 | /* we can use hardcoded curve for plain SRGB TF */ |
2134 | if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true1 && |
2135 | output_tf->tf == TRANSFER_FUNCTION_SRGB) { |
2136 | if (ramp == NULL((void *)0)) |
2137 | return true1; |
2138 | if ((ramp->is_identity && ramp->type != GAMMA_CS_TFM_1D) || |
2139 | (!mapUserRamp && ramp->type == GAMMA_RGB_256)) |
2140 | return true1; |
2141 | } |
2142 | |
2143 | output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; |
2144 | |
2145 | if (ramp && ramp->type != GAMMA_CS_TFM_1D && |
2146 | (mapUserRamp || ramp->type != GAMMA_RGB_256)) { |
2147 | rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS3, |
2148 | sizeof(*rgb_user), |
2149 | GFP_KERNEL(0x0001 | 0x0004)); |
2150 | if (!rgb_user) |
2151 | goto rgb_user_alloc_fail; |
2152 | |
2153 | axis_x = kvcalloc(ramp->num_entries + 3, sizeof(*axis_x), |
2154 | GFP_KERNEL(0x0001 | 0x0004)); |
2155 | if (!axis_x) |
2156 | goto axis_x_alloc_fail; |
2157 | |
2158 | dividers.divider1 = dc_fixpt_from_fraction(3, 2); |
2159 | dividers.divider2 = dc_fixpt_from_int(2); |
2160 | dividers.divider3 = dc_fixpt_from_fraction(5, 2); |
2161 | |
2162 | build_evenly_distributed_points( |
2163 | axis_x, |
2164 | ramp->num_entries, |
2165 | dividers); |
2166 | |
2167 | if (ramp->type == GAMMA_RGB_256 && mapUserRamp) |
2168 | scale_gamma(rgb_user, ramp, dividers); |
2169 | else if (ramp->type == GAMMA_RGB_FLOAT_1024) |
2170 | scale_gamma_dx(rgb_user, ramp, dividers); |
2171 | } |
2172 | |
2173 | rgb_regamma = kvcalloc(MAX_HW_POINTS(16*32) + _EXTRA_POINTS3, |
2174 | sizeof(*rgb_regamma), |
2175 | GFP_KERNEL(0x0001 | 0x0004)); |
2176 | if (!rgb_regamma) |
2177 | goto rgb_regamma_alloc_fail; |
2178 | |
2179 | coeff = kvcalloc(MAX_HW_POINTS(16*32) + _EXTRA_POINTS3, sizeof(*coeff), |
2180 | GFP_KERNEL(0x0001 | 0x0004)); |
2181 | if (!coeff) |
2182 | goto coeff_alloc_fail; |
2183 | |
2184 | tf = output_tf->tf; |
2185 | |
2186 | ret = calculate_curve(tf, |
2187 | tf_pts, |
2188 | rgb_regamma, |
2189 | fs_params, |
2190 | output_tf->sdr_ref_white_level, |
2191 | cal_buffer); |
2192 | |
2193 | if (ret) { |
2194 | doClamping = !(output_tf->tf == TRANSFER_FUNCTION_GAMMA22 && |
2195 | fs_params != NULL((void *)0) && fs_params->skip_tm == 0); |
2196 | |
2197 | map_regamma_hw_to_x_user(ramp, coeff, rgb_user, |
2198 | coordinates_x, axis_x, rgb_regamma, |
2199 | MAX_HW_POINTS(16*32), tf_pts, |
2200 | (mapUserRamp || (ramp && ramp->type != GAMMA_RGB_256)) && |
2201 | (ramp && ramp->type != GAMMA_CS_TFM_1D), |
2202 | doClamping); |
2203 | |
2204 | if (ramp && ramp->type == GAMMA_CS_TFM_1D) |
2205 | apply_lut_1d(ramp, MAX_HW_POINTS(16*32), tf_pts); |
2206 | } |
2207 | |
2208 | kvfree(coeff); |
2209 | coeff_alloc_fail: |
2210 | kvfree(rgb_regamma); |
2211 | rgb_regamma_alloc_fail: |
2212 | kvfree(axis_x); |
2213 | axis_x_alloc_fail: |
2214 | kvfree(rgb_user); |
2215 | rgb_user_alloc_fail: |
2216 | return ret; |
2217 | } |
2218 | |
2219 | bool_Bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, |
2220 | struct dc_transfer_func_distributed_points *points) |
2221 | { |
2222 | uint32_t i; |
2223 | bool_Bool ret = false0; |
2224 | struct pwl_float_data_ex *rgb_degamma = NULL((void *)0); |
2225 | |
2226 | if (trans == TRANSFER_FUNCTION_UNITY || |
2227 | trans == TRANSFER_FUNCTION_LINEAR) { |
2228 | |
2229 | for (i = 0; i <= MAX_HW_POINTS(16*32) ; i++) { |
2230 | points->red[i] = coordinates_x[i].x; |
2231 | points->green[i] = coordinates_x[i].x; |
2232 | points->blue[i] = coordinates_x[i].x; |
2233 | } |
2234 | ret = true1; |
2235 | } else if (trans == TRANSFER_FUNCTION_PQ) { |
2236 | rgb_degamma = kvcalloc(MAX_HW_POINTS(16*32) + _EXTRA_POINTS3, |
2237 | sizeof(*rgb_degamma), |
2238 | GFP_KERNEL(0x0001 | 0x0004)); |
2239 | if (!rgb_degamma) |
2240 | goto rgb_degamma_alloc_fail; |
2241 | |
2242 | |
2243 | build_de_pq(rgb_degamma, |
2244 | MAX_HW_POINTS(16*32), |
2245 | coordinates_x); |
2246 | for (i = 0; i <= MAX_HW_POINTS(16*32) ; i++) { |
2247 | points->red[i] = rgb_degamma[i].r; |
2248 | points->green[i] = rgb_degamma[i].g; |
2249 | points->blue[i] = rgb_degamma[i].b; |
2250 | } |
2251 | ret = true1; |
2252 | |
2253 | kvfree(rgb_degamma); |
2254 | } else if (trans == TRANSFER_FUNCTION_SRGB || |
2255 | trans == TRANSFER_FUNCTION_BT709 || |
2256 | trans == TRANSFER_FUNCTION_GAMMA22 || |
2257 | trans == TRANSFER_FUNCTION_GAMMA24 || |
2258 | trans == TRANSFER_FUNCTION_GAMMA26) { |
2259 | rgb_degamma = kvcalloc(MAX_HW_POINTS(16*32) + _EXTRA_POINTS3, |
2260 | sizeof(*rgb_degamma), |
2261 | GFP_KERNEL(0x0001 | 0x0004)); |
2262 | if (!rgb_degamma) |
2263 | goto rgb_degamma_alloc_fail; |
2264 | |
2265 | build_degamma(rgb_degamma, |
2266 | MAX_HW_POINTS(16*32), |
2267 | coordinates_x, |
2268 | trans); |
2269 | for (i = 0; i <= MAX_HW_POINTS(16*32) ; i++) { |
2270 | points->red[i] = rgb_degamma[i].r; |
2271 | points->green[i] = rgb_degamma[i].g; |
2272 | points->blue[i] = rgb_degamma[i].b; |
2273 | } |
2274 | ret = true1; |
2275 | |
2276 | kvfree(rgb_degamma); |
2277 | } else if (trans == TRANSFER_FUNCTION_HLG) { |
2278 | rgb_degamma = kvcalloc(MAX_HW_POINTS(16*32) + _EXTRA_POINTS3, |
2279 | sizeof(*rgb_degamma), |
2280 | GFP_KERNEL(0x0001 | 0x0004)); |
2281 | if (!rgb_degamma) |
2282 | goto rgb_degamma_alloc_fail; |
2283 | |
2284 | build_hlg_degamma(rgb_degamma, |
2285 | MAX_HW_POINTS(16*32), |
2286 | coordinates_x, |
2287 | 80, 1000); |
2288 | for (i = 0; i <= MAX_HW_POINTS(16*32) ; i++) { |
2289 | points->red[i] = rgb_degamma[i].r; |
2290 | points->green[i] = rgb_degamma[i].g; |
2291 | points->blue[i] = rgb_degamma[i].b; |
2292 | } |
2293 | ret = true1; |
2294 | kvfree(rgb_degamma); |
2295 | } |
2296 | points->end_exponent = 0; |
2297 | points->x_point_at_y1_red = 1; |
2298 | points->x_point_at_y1_green = 1; |
2299 | points->x_point_at_y1_blue = 1; |
2300 | |
2301 | rgb_degamma_alloc_fail: |
2302 | return ret; |
2303 | } |