Bug Summary

File:dev/pci/drm/amd/display/modules/color/color_gamma.c
Warning:line 869, column 20
Value stored to 'a' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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