1 /* Copyright 2022 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a
4 * copy of this software and associated documentation files (the "Software"),
5 * to deal in the Software without restriction, including without limitation
6 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 * and/or sell copies of the Software, and to permit persons to whom the
8 * Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19 * OTHER DEALINGS IN THE SOFTWARE.
20 *
21 * Authors: AMD
22 *
23 */
24
25 #include <string.h>
26 #include "common.h"
27 #include "vpe_priv.h"
28 #include "color.h"
29 #include "color_gamma.h"
30 #include "hw_shared.h"
31
32 #define PRECISE_LUT_REGION_START 224
33 #define PRECISE_LUT_REGION_END 239
34
35 static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2];
36 static struct hw_x_point coordinates_x_degamma[MAX_HW_POINTS_DEGAMMA];
37
38 // these are helpers for calculations to reduce stack usage
39 // do not depend on these being preserved across calls
40
41 /* Helper to optimize gamma calculation, only use in translate_from_linear, in
42 * particular the vpe_fixpt_pow function which is very expensive
43 * The idea is that our regions for X points are exponential and currently they all use
44 * the same number of points (NUM_PTS_IN_REGION) and in each region every point
45 * is exactly 2x the one at the same index in the previous region. In other words
46 * X[i] = 2 * X[i-NUM_PTS_IN_REGION] for i>=16
47 * The other fact is that (2x)^gamma = 2^gamma * x^gamma
48 * So we compute and save x^gamma for the first 16 regions, and for every next region
49 * just multiply with 2^gamma which can be computed once, and save the result so we
50 * recursively compute all the values.
51 */
52
53 /*
54 * Regamma coefficients are used for both regamma and degamma. Degamma
55 * coefficients are calculated in our formula using the regamma coefficients.
56 */
57 /*sRGB 709 2.2 2.4 P3*/
58 static const int32_t numerator01[] = {31308, 180000, 0, 0, 0};
59 static const int32_t numerator02[] = {12920, 4500, 0, 0, 0};
60 static const int32_t numerator03[] = {55, 99, 0, 0, 0};
61 static const int32_t numerator04[] = {55, 99, 0, 0, 0};
62 static const int32_t numerator05[] = {
63 2400, 2222, 2200, 2400, 2600}; // the standard REC 709 states 0.45. Inverse of that is 2.22
64
65 /* one-time setup of X points */
vpe_color_setup_x_points_distribution(void)66 void vpe_color_setup_x_points_distribution(void)
67 {
68 struct fixed31_32 region_size = vpe_fixpt_from_int(128);
69 int32_t segment;
70 uint32_t seg_offset;
71 uint32_t index;
72 struct fixed31_32 increment;
73
74 coordinates_x[MAX_HW_POINTS].x = region_size;
75 coordinates_x[MAX_HW_POINTS + 1].x = region_size;
76
77 for (segment = 6; segment > (6 - NUM_REGIONS); segment--) {
78 region_size = vpe_fixpt_div_int(region_size, 2);
79 increment = vpe_fixpt_div_int(region_size, NUM_PTS_IN_REGION);
80 seg_offset = (uint32_t)((segment + (NUM_REGIONS - 7)) * NUM_PTS_IN_REGION);
81
82 coordinates_x[seg_offset].x = region_size;
83
84 for (index = seg_offset + 1; index < seg_offset + NUM_PTS_IN_REGION; index++) {
85 coordinates_x[index].x = vpe_fixpt_add(coordinates_x[index - 1].x, increment);
86 }
87 }
88 }
89
90 /* Setting up x points for DEGAMMA once */
vpe_color_setup_x_points_distribution_degamma(void)91 void vpe_color_setup_x_points_distribution_degamma(void)
92 {
93 struct fixed31_32 region_size = vpe_fixpt_from_int(1);
94 int32_t segment;
95 uint32_t index = 0;
96 uint32_t numptsdegamma = 1;
97 uint32_t segment_offset;
98
99 /* Since region = -8 only has 1 point setting it up before the loop */
100 coordinates_x_degamma[0].x = vpe_fixpt_div(vpe_fixpt_from_int(1), vpe_fixpt_from_int(512));
101
102 for (segment = -7; segment <= 0; segment++) {
103 segment_offset = numptsdegamma;
104 numptsdegamma *= 2;
105
106 for (index = segment_offset; index < numptsdegamma; index++) {
107 coordinates_x_degamma[index].x =
108 vpe_fixpt_div(vpe_fixpt_from_int(index), vpe_fixpt_from_int(256));
109 }
110 }
111 coordinates_x_degamma[MAX_HW_POINTS_DEGAMMA - 1].x = region_size;
112 }
113
vpe_compute_pq(struct fixed31_32 in_x,struct fixed31_32 * out_y)114 void vpe_compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
115 {
116 /* consts for PQ gamma formula. */
117 const struct fixed31_32 m1 = vpe_fixpt_from_fraction(159301758, 1000000000);
118 const struct fixed31_32 m2 = vpe_fixpt_from_fraction(7884375, 100000);
119 const struct fixed31_32 c1 = vpe_fixpt_from_fraction(8359375, 10000000);
120 const struct fixed31_32 c2 = vpe_fixpt_from_fraction(188515625, 10000000);
121 const struct fixed31_32 c3 = vpe_fixpt_from_fraction(186875, 10000);
122
123 struct fixed31_32 l_pow_m1;
124 struct fixed31_32 base;
125
126 // Power function will fail if < this value
127 struct fixed31_32 min = {0x000000000000000010};
128
129 if (vpe_fixpt_le(vpe_fixpt_one, in_x)) {
130 *out_y = vpe_fixpt_one;
131 return;
132 }
133
134 if (vpe_fixpt_lt(in_x, min))
135 in_x = vpe_fixpt_zero;
136
137 l_pow_m1 = vpe_fixpt_pow(in_x, m1);
138 base = vpe_fixpt_div(vpe_fixpt_add(c1, (vpe_fixpt_mul(c2, l_pow_m1))),
139 vpe_fixpt_add(vpe_fixpt_one, (vpe_fixpt_mul(c3, l_pow_m1))));
140 *out_y = vpe_fixpt_pow(base, m2);
141 }
142
compute_de_pq(struct fixed31_32 in_x,struct fixed31_32 * out_y)143 static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
144 {
145 /* consts for dePQ gamma formula. */
146 const struct fixed31_32 m1 = vpe_fixpt_from_fraction(159301758, 1000000000);
147 const struct fixed31_32 m2 = vpe_fixpt_from_fraction(7884375, 100000);
148 const struct fixed31_32 c1 = vpe_fixpt_from_fraction(8359375, 10000000);
149 const struct fixed31_32 c2 = vpe_fixpt_from_fraction(188515625, 10000000);
150 const struct fixed31_32 c3 = vpe_fixpt_from_fraction(186875, 10000);
151
152 struct fixed31_32 l_pow_m1;
153 struct fixed31_32 base, div;
154 struct fixed31_32 base2;
155
156 if (vpe_fixpt_lt(in_x, vpe_fixpt_zero))
157 in_x = vpe_fixpt_zero;
158
159 if (vpe_fixpt_le(vpe_fixpt_one, in_x)) {
160 *out_y = vpe_fixpt_one;
161 return;
162 }
163
164 l_pow_m1 = vpe_fixpt_pow(in_x, vpe_fixpt_div(vpe_fixpt_one, m2));
165 base = vpe_fixpt_sub(l_pow_m1, c1);
166
167 div = vpe_fixpt_sub(c2, vpe_fixpt_mul(c3, l_pow_m1));
168
169 base2 = vpe_fixpt_div(base, div);
170 // avoid complex numbers
171 if (vpe_fixpt_lt(base2, vpe_fixpt_zero))
172 base2 = vpe_fixpt_sub(vpe_fixpt_zero, base2);
173
174 *out_y = vpe_fixpt_pow(base2, vpe_fixpt_div(vpe_fixpt_one, m1));
175 }
176
177 /* one-time pre-compute PQ values - only for sdr_white_level 80 */
precompute_pq(void)178 static void precompute_pq(void)
179 {
180 int i;
181 struct fixed31_32 x;
182 const struct hw_x_point *coord_x = coordinates_x + 32;
183 struct fixed31_32 scaling_factor = vpe_fixpt_from_fraction(80, 10000);
184
185 struct fixed31_32 *pq_table = vpe_color_get_table(type_pq_table);
186
187 /* pow function has problems with arguments too small */
188 for (i = 0; i < 32; i++)
189 pq_table[i] = vpe_fixpt_zero;
190
191 for (i = 32; i <= MAX_HW_POINTS; i++) {
192 x = vpe_fixpt_mul(coord_x->x, scaling_factor);
193 vpe_compute_pq(x, &pq_table[i]);
194 ++coord_x;
195 }
196 }
197
198 /* one-time pre-compute dePQ values - only for max pixel value 125 FP16.
199 yuv2rgbScaling is used when the output yuv->rgb is scaled down
200 due to limited range of the yuv2rgb matrix
201 */
202
precompute_de_pq(struct fixed31_32 x_scale,struct fixed31_32 y_scale)203 static void precompute_de_pq(struct fixed31_32 x_scale, struct fixed31_32 y_scale)
204 {
205 uint32_t i;
206 struct fixed31_32 y;
207 struct fixed31_32 *de_pq_table = vpe_color_get_table(type_de_pq_table);
208
209 for (i = 0; i < MAX_HW_POINTS_DEGAMMA; i++) {
210 compute_de_pq(vpe_fixpt_mul(coordinates_x_degamma[i].x, x_scale), &y);
211 de_pq_table[i] = vpe_fixpt_mul(y, y_scale);
212 }
213 }
214
build_coefficients(struct gamma_coefficients * coefficients,enum color_transfer_func type)215 static bool build_coefficients(
216 struct gamma_coefficients *coefficients, enum color_transfer_func type)
217 {
218
219 uint32_t i = 0;
220 uint32_t index = 0;
221 bool ret = true;
222
223 if (type == TRANSFER_FUNC_SRGB)
224 index = 0;
225 else if (type == TRANSFER_FUNC_BT709)
226 index = 1;
227 else if (type == TRANSFER_FUNC_BT1886)
228 index = 3;
229 else {
230 VPE_ASSERT(0);
231 ret = false;
232 goto release;
233 }
234
235 do {
236 coefficients->a0[i] = vpe_fixpt_from_fraction(numerator01[index], 10000000);
237 coefficients->a1[i] = vpe_fixpt_from_fraction(numerator02[index], 1000);
238 coefficients->a2[i] = vpe_fixpt_from_fraction(numerator03[index], 1000);
239 coefficients->a3[i] = vpe_fixpt_from_fraction(numerator04[index], 1000);
240 coefficients->user_gamma[i] = vpe_fixpt_from_fraction(numerator05[index], 1000);
241
242 ++i;
243 } while (i != ARRAY_SIZE(coefficients->a0));
244 release:
245 return ret;
246 }
247
248 // bt.1886
translate_to_linear_space(struct fixed31_32 arg,struct fixed31_32 a0,struct fixed31_32 a1,struct fixed31_32 a2,struct fixed31_32 a3,struct fixed31_32 gamma)249 static struct fixed31_32 translate_to_linear_space(struct fixed31_32 arg, struct fixed31_32 a0,
250 struct fixed31_32 a1, struct fixed31_32 a2, struct fixed31_32 a3, struct fixed31_32 gamma)
251 {
252 struct fixed31_32 linear;
253
254 a0 = vpe_fixpt_mul(a0, a1);
255 if (vpe_fixpt_le(arg, vpe_fixpt_neg(a0)))
256
257 linear = vpe_fixpt_neg(vpe_fixpt_pow(
258 vpe_fixpt_div(vpe_fixpt_sub(a2, arg), vpe_fixpt_add(vpe_fixpt_one, a3)), gamma));
259
260 else if (vpe_fixpt_le(vpe_fixpt_neg(a0), arg) && vpe_fixpt_le(arg, a0))
261 linear = vpe_fixpt_div(arg, a1);
262 else
263 linear = vpe_fixpt_pow(
264 vpe_fixpt_div(vpe_fixpt_add(a2, arg), vpe_fixpt_add(vpe_fixpt_one, a3)), gamma);
265
266 return linear;
267 }
268
translate_to_linear_space_ex(struct fixed31_32 arg,struct gamma_coefficients * coeff,uint32_t color_index)269 static inline struct fixed31_32 translate_to_linear_space_ex(
270 struct fixed31_32 arg, struct gamma_coefficients *coeff, uint32_t color_index)
271 {
272 if (vpe_fixpt_le(vpe_fixpt_one, arg))
273 return vpe_fixpt_one;
274
275 return translate_to_linear_space(arg, coeff->a0[color_index], coeff->a1[color_index],
276 coeff->a2[color_index], coeff->a3[color_index], coeff->user_gamma[color_index]);
277 }
278
translate_from_linear_space(struct translate_from_linear_space_args * args)279 static struct fixed31_32 translate_from_linear_space(struct translate_from_linear_space_args *args)
280 {
281 const struct fixed31_32 one = vpe_fixpt_from_int(1);
282
283 struct fixed31_32 scratch_1, scratch_2;
284 struct calculate_buffer *cal_buffer = args->cal_buffer;
285
286 if (vpe_fixpt_le(one, args->arg))
287 return one;
288
289 if (vpe_fixpt_le(args->arg, vpe_fixpt_neg(args->a0))) {
290 scratch_1 = vpe_fixpt_add(one, args->a3);
291 scratch_2 = vpe_fixpt_pow(vpe_fixpt_neg(args->arg), vpe_fixpt_recip(args->gamma));
292 scratch_1 = vpe_fixpt_mul(scratch_1, scratch_2);
293 scratch_1 = vpe_fixpt_sub(args->a2, scratch_1);
294
295 return scratch_1;
296 } else if (vpe_fixpt_le(args->a0, args->arg)) {
297 if (cal_buffer->buffer_index == 0) {
298 cal_buffer->gamma_of_2 =
299 vpe_fixpt_pow(vpe_fixpt_from_int(2), vpe_fixpt_recip(args->gamma));
300 }
301 scratch_1 = vpe_fixpt_add(one, args->a3);
302 // In the first region (first 16 points) and in the
303 // region delimited by START/END we calculate with
304 // full precision to avoid error accumulation.
305 if ((cal_buffer->buffer_index >= PRECISE_LUT_REGION_START &&
306 cal_buffer->buffer_index <= PRECISE_LUT_REGION_END) ||
307 (cal_buffer->buffer_index < 16))
308 scratch_2 = vpe_fixpt_pow(args->arg, vpe_fixpt_recip(args->gamma));
309 else
310 scratch_2 = vpe_fixpt_mul(
311 cal_buffer->gamma_of_2, cal_buffer->buffer[cal_buffer->buffer_index % 16]);
312
313 if (cal_buffer->buffer_index != -1) {
314 cal_buffer->buffer[cal_buffer->buffer_index % 16] = scratch_2;
315 cal_buffer->buffer_index++;
316 }
317
318 scratch_1 = vpe_fixpt_mul(scratch_1, scratch_2);
319 scratch_1 = vpe_fixpt_sub(scratch_1, args->a2);
320
321 return scratch_1;
322 } else
323 return vpe_fixpt_mul(args->arg, args->a1);
324 }
325
translate_from_linear_space_ex(struct fixed31_32 arg,struct gamma_coefficients * coeff,uint32_t color_index,struct calculate_buffer * cal_buffer)326 static struct fixed31_32 translate_from_linear_space_ex(struct fixed31_32 arg,
327 struct gamma_coefficients *coeff, uint32_t color_index, struct calculate_buffer *cal_buffer)
328 {
329 struct translate_from_linear_space_args scratch_gamma_args = {0};
330
331 scratch_gamma_args.arg = arg;
332 scratch_gamma_args.a0 = coeff->a0[color_index];
333 scratch_gamma_args.a1 = coeff->a1[color_index];
334 scratch_gamma_args.a2 = coeff->a2[color_index];
335 scratch_gamma_args.a3 = coeff->a3[color_index];
336 scratch_gamma_args.gamma = coeff->user_gamma[color_index];
337 scratch_gamma_args.cal_buffer = cal_buffer;
338
339 return translate_from_linear_space(&scratch_gamma_args);
340 }
341
build_pq(uint32_t hw_points_num,const struct hw_x_point * coordinate_x,struct fixed31_32 x_scale,struct fixed31_32 y_scale,struct pwl_float_data_ex * rgb_regamma)342 static void build_pq(uint32_t hw_points_num, const struct hw_x_point *coordinate_x,
343 struct fixed31_32 x_scale, struct fixed31_32 y_scale, struct pwl_float_data_ex *rgb_regamma)
344 {
345 uint32_t i, curve_start_index;
346
347 struct pwl_float_data_ex *rgb = rgb_regamma;
348 const struct hw_x_point *coord_x = coordinate_x;
349 struct fixed31_32 output;
350 struct fixed31_32 slope;
351
352 /* Curve Start index is from segment 2^-24, the first segment must be
353 * treated as a linear interpolation due to numbers being to small for power
354 * operations
355 */
356 curve_start_index = 32;
357 vpe_compute_pq(vpe_fixpt_mul(coord_x[curve_start_index].x, x_scale), &output);
358 output = vpe_fixpt_mul(output, y_scale);
359 slope = vpe_fixpt_div(output, coord_x[curve_start_index].x);
360
361 for (i = 0; i < curve_start_index; i++) {
362 output = vpe_fixpt_mul(coord_x->x, slope);
363 rgb->r = output;
364 rgb->g = output;
365 rgb->b = output;
366
367 ++coord_x;
368 ++rgb;
369 }
370
371 for (i = curve_start_index; i <= hw_points_num; i++) {
372
373 vpe_compute_pq(vpe_fixpt_mul(coord_x->x, x_scale), &output);
374 output = vpe_fixpt_mul(output, y_scale);
375 rgb->r = output;
376 rgb->g = output;
377 rgb->b = output;
378
379 ++coord_x;
380 ++rgb;
381 }
382 }
383
build_de_pq(uint32_t hw_points_num,const struct hw_x_point * coordinate_x_degamma,struct fixed31_32 x_scale,struct fixed31_32 y_scale,struct transfer_func_distributed_points * de_pq)384 static void build_de_pq(uint32_t hw_points_num, const struct hw_x_point *coordinate_x_degamma,
385 struct fixed31_32 x_scale, struct fixed31_32 y_scale,
386 struct transfer_func_distributed_points *de_pq)
387 {
388 struct fixed31_32 output;
389
390 for (uint32_t i = 0; i < hw_points_num; i++) {
391 compute_de_pq(vpe_fixpt_mul(coordinates_x_degamma[i].x, x_scale), &output);
392 output = vpe_fixpt_mul(output, y_scale);
393 de_pq->red[i] = output;
394 de_pq->green[i] = output;
395 de_pq->blue[i] = output;
396 }
397 }
398
build_degamma(uint32_t hw_points_num,const struct hw_x_point * coordinate_x_degamma,enum color_transfer_func type,struct fixed31_32 x_scale,struct fixed31_32 y_scale,struct transfer_func_distributed_points * curve)399 static bool build_degamma(uint32_t hw_points_num, const struct hw_x_point *coordinate_x_degamma,
400 enum color_transfer_func type, struct fixed31_32 x_scale, struct fixed31_32 y_scale,
401 struct transfer_func_distributed_points *curve)
402 {
403 uint32_t i;
404 struct gamma_coefficients coeff;
405 struct fixed31_32 output;
406 bool ret = false;
407
408 if (!build_coefficients(&coeff, type))
409 goto release;
410
411 /* De-gamma X is 2^-8 to 2^0 i.e. 9 regions
412 */
413
414 i = 0;
415 while (i != MAX_HW_POINTS_DEGAMMA) {
416 output = vpe_fixpt_mul(coordinate_x_degamma[i].x, x_scale);
417
418 output = translate_to_linear_space_ex(output, &coeff, 0);
419 output = vpe_fixpt_mul(output, y_scale);
420
421 curve->red[i] = output;
422 curve->green[i] = output;
423 curve->blue[i] = output;
424 i++;
425 }
426 ret = true;
427 release:
428 return ret;
429 }
430
build_regamma(struct vpe_priv * vpe_priv,uint32_t hw_points_num,const struct hw_x_point * coordinate_x,enum color_transfer_func type,struct fixed31_32 x_scale,struct fixed31_32 y_scale,struct calculate_buffer * cal_buffer,struct pwl_float_data_ex * rgb_regamma)431 static bool build_regamma(struct vpe_priv *vpe_priv, uint32_t hw_points_num,
432 const struct hw_x_point *coordinate_x, enum color_transfer_func type, struct fixed31_32 x_scale,
433 struct fixed31_32 y_scale, struct calculate_buffer *cal_buffer,
434 struct pwl_float_data_ex *rgb_regamma)
435 {
436 uint32_t i;
437 bool ret = false;
438
439 struct gamma_coefficients *coeff;
440 struct pwl_float_data_ex *rgb = rgb_regamma;
441 const struct hw_x_point *coord_x = coordinate_x;
442
443 coeff = (struct gamma_coefficients *)vpe_zalloc(sizeof(*coeff));
444 if (!coeff)
445 goto release;
446
447 if (!build_coefficients(coeff, type))
448 goto release;
449
450 memset(cal_buffer->buffer, 0, NUM_PTS_IN_REGION * sizeof(struct fixed31_32));
451 cal_buffer->buffer_index = 0; // see variable definition for more info
452
453 i = 0;
454 while (i <= hw_points_num) {
455 rgb->r = vpe_fixpt_mul(coord_x->x, x_scale);
456 rgb->r = translate_from_linear_space_ex(rgb->r, coeff, 0, cal_buffer);
457 rgb->r = vpe_fixpt_mul(rgb->r, y_scale);
458 rgb->g = rgb->r;
459 rgb->b = rgb->r;
460 ++coord_x;
461 ++rgb;
462 ++i;
463 }
464 cal_buffer->buffer_index = -1;
465 ret = true;
466 release:
467 vpe_free(coeff);
468 return ret;
469 }
470
build_new_custom_resulted_curve(uint32_t hw_points_num,struct transfer_func_distributed_points * tf_pts)471 static void build_new_custom_resulted_curve(
472 uint32_t hw_points_num, struct transfer_func_distributed_points *tf_pts)
473 {
474 uint32_t i = 0;
475
476 while (i != hw_points_num + 1) {
477 tf_pts->red[i] = vpe_fixpt_clamp(tf_pts->red[i], vpe_fixpt_zero, vpe_fixpt_one);
478 tf_pts->green[i] = vpe_fixpt_clamp(tf_pts->green[i], vpe_fixpt_zero, vpe_fixpt_one);
479 tf_pts->blue[i] = vpe_fixpt_clamp(tf_pts->blue[i], vpe_fixpt_zero, vpe_fixpt_one);
480
481 ++i;
482 }
483 }
484
map_regamma_hw_to_x_user(struct hw_x_point * coords_x,const struct pwl_float_data_ex * rgb_regamma,uint32_t hw_points_num,struct transfer_func_distributed_points * tf_pts,bool doClamping)485 static bool map_regamma_hw_to_x_user(struct hw_x_point *coords_x, const struct pwl_float_data_ex *rgb_regamma,
486 uint32_t hw_points_num, struct transfer_func_distributed_points *tf_pts, bool doClamping)
487 {
488 /* setup to spare calculated ideal regamma values */
489
490 uint32_t i = 0;
491 struct hw_x_point *coords = coords_x;
492 const struct pwl_float_data_ex *regamma = rgb_regamma;
493
494 /* just copy current rgb_regamma into tf_pts */
495 while (i <= hw_points_num) {
496 tf_pts->red[i] = regamma->r;
497 tf_pts->green[i] = regamma->g;
498 tf_pts->blue[i] = regamma->b;
499
500 ++regamma;
501 ++i;
502 }
503
504 if (doClamping) {
505 /* this should be named differently, all it does is clamp to 0-1 */
506 build_new_custom_resulted_curve(hw_points_num, tf_pts);
507 }
508
509 return true;
510 }
511
calculate_curve(struct vpe_priv * vpe_priv,enum color_transfer_func trans,struct fixed31_32 x_scale,struct fixed31_32 y_scale,struct transfer_func_distributed_points * points,struct pwl_float_data_ex * rgb_regamma,struct calculate_buffer * cal_buffer)512 static bool calculate_curve(struct vpe_priv *vpe_priv, enum color_transfer_func trans,
513 struct fixed31_32 x_scale, struct fixed31_32 y_scale,
514 struct transfer_func_distributed_points *points, struct pwl_float_data_ex *rgb_regamma,
515 struct calculate_buffer *cal_buffer)
516 {
517 int hdr_norm = vpe_priv->resource.internal_hdr_normalization;
518 struct fixed31_32 combined_scale;
519
520 bool ret = false;
521 switch (trans)
522 {
523 case TRANSFER_FUNC_SRGB:
524 case TRANSFER_FUNC_BT709:
525 case TRANSFER_FUNC_BT1886:
526 build_regamma(vpe_priv, MAX_HW_POINTS, coordinates_x, trans, x_scale, y_scale, cal_buffer,
527 rgb_regamma);
528 ret = true;
529 break;
530 case TRANSFER_FUNC_PQ2084:
531 build_pq(MAX_HW_POINTS, coordinates_x, x_scale, y_scale, rgb_regamma);
532 ret = true;
533 break;
534 case TRANSFER_FUNC_LINEAR:
535 combined_scale = vpe_fixpt_div_int(vpe_fixpt_one, hdr_norm);
536 combined_scale = vpe_fixpt_mul(combined_scale, y_scale);
537 combined_scale = vpe_fixpt_mul(combined_scale, x_scale);
538 for (int i = 0; i < MAX_HW_POINTS; i++) {
539 rgb_regamma[i].r = vpe_fixpt_mul(coordinates_x[i].x, combined_scale);
540 rgb_regamma[i].g = rgb_regamma[i].r;
541 rgb_regamma[i].b = rgb_regamma[i].r;
542 }
543
544 ret = true;
545 break;
546 case TRANSFER_FUNC_NORMALIZED_PQ:
547 case TRANSFER_FUNC_UNKNOWN:
548 break;
549 default:
550 break;
551 }
552
553 return ret;
554 }
555
556 #define _EXTRA_POINTS 3
557
vpe_color_calculate_degamma_params(struct vpe_priv * vpe_priv,struct fixed31_32 x_scale,struct fixed31_32 y_scale,struct transfer_func * input_tf)558 bool vpe_color_calculate_degamma_params(struct vpe_priv *vpe_priv, struct fixed31_32 x_scale,
559 struct fixed31_32 y_scale, struct transfer_func *input_tf)
560 {
561 struct transfer_func_distributed_points *tf_pts = &input_tf->tf_pts;
562 enum color_transfer_func tf = input_tf->tf;
563 int hdr_norm = vpe_priv->resource.internal_hdr_normalization;
564 bool ret = false;
565 struct fixed31_32 scale_combined;
566 struct fixed31_32 output;
567
568
569
570 switch (tf)
571 {
572 case TRANSFER_FUNC_PQ2084:
573 case TRANSFER_FUNC_NORMALIZED_PQ:
574 build_de_pq(MAX_HW_POINTS_DEGAMMA, coordinates_x_degamma, x_scale, y_scale, tf_pts);
575 ret = true;
576 break;
577 case TRANSFER_FUNC_SRGB:
578 case TRANSFER_FUNC_BT709:
579 case TRANSFER_FUNC_BT1886:
580 build_degamma(MAX_HW_POINTS_DEGAMMA, coordinates_x_degamma, tf, x_scale, y_scale, tf_pts);
581 ret = true;
582 break;
583 case TRANSFER_FUNC_LINEAR:
584 scale_combined = vpe_fixpt_mul(vpe_fixpt_from_int(hdr_norm), x_scale);
585 scale_combined = vpe_fixpt_mul(scale_combined, y_scale);
586
587 for (int i = 0; i < MAX_HW_POINTS_DEGAMMA; i ++) {
588 output = vpe_fixpt_mul(coordinates_x_degamma[i].x, scale_combined);
589 tf_pts->red[i] = output;
590 tf_pts->green[i] = output;
591 tf_pts->blue[i] = output;
592 }
593 ret = true;
594 break;
595 default:
596 break;
597 }
598 return ret;
599 }
600
vpe_color_calculate_regamma_params(struct vpe_priv * vpe_priv,struct fixed31_32 x_scale,struct fixed31_32 y_scale,struct calculate_buffer * cal_buffer,struct transfer_func * output_tf)601 bool vpe_color_calculate_regamma_params(struct vpe_priv *vpe_priv, struct fixed31_32 x_scale,
602 struct fixed31_32 y_scale, struct calculate_buffer *cal_buffer, struct transfer_func *output_tf)
603 {
604 struct transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
605 struct pwl_float_data_ex *rgb_regamma = NULL;
606 struct pixel_gamma_point *coeff = NULL;
607 enum color_transfer_func tf;
608 bool ret = false;
609
610 rgb_regamma = (struct pwl_float_data_ex *)vpe_zalloc(
611 (MAX_HW_POINTS + _EXTRA_POINTS) * sizeof(*rgb_regamma));
612 if (!rgb_regamma)
613 goto rgb_regamma_alloc_fail;
614
615 coeff =
616 (struct pixel_gamma_point *)vpe_zalloc((MAX_HW_POINTS + _EXTRA_POINTS) * sizeof(*coeff));
617 if (!coeff)
618 goto coeff_alloc_fail;
619
620 tf = output_tf->tf;
621
622 ret = calculate_curve(vpe_priv, tf, x_scale, y_scale, tf_pts, rgb_regamma, cal_buffer);
623
624 if (ret) {
625 map_regamma_hw_to_x_user(coordinates_x, rgb_regamma, MAX_HW_POINTS, tf_pts, false);
626 }
627
628 vpe_free(coeff);
629 coeff_alloc_fail:
630 vpe_free(rgb_regamma);
631 rgb_regamma_alloc_fail:
632 return ret;
633 }
634