xref: /aosp_15_r20/external/mesa3d/src/amd/vpelib/src/core/color_gamma.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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     if (vpe_fixpt_le(vpe_fixpt_one, in_x)) {
127         *out_y = vpe_fixpt_one;
128         return;
129     }
130 
131     if (vpe_fixpt_lt(in_x, vpe_fixpt_zero))
132         in_x = vpe_fixpt_zero;
133 
134     l_pow_m1 = vpe_fixpt_pow(in_x, m1);
135     base     = vpe_fixpt_div(vpe_fixpt_add(c1, (vpe_fixpt_mul(c2, l_pow_m1))),
136             vpe_fixpt_add(vpe_fixpt_one, (vpe_fixpt_mul(c3, l_pow_m1))));
137     *out_y   = vpe_fixpt_pow(base, m2);
138 }
139 
compute_de_pq(struct fixed31_32 in_x,struct fixed31_32 * out_y)140 static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
141 {
142     /* consts for dePQ gamma formula. */
143     const struct fixed31_32 m1 = vpe_fixpt_from_fraction(159301758, 1000000000);
144     const struct fixed31_32 m2 = vpe_fixpt_from_fraction(7884375, 100000);
145     const struct fixed31_32 c1 = vpe_fixpt_from_fraction(8359375, 10000000);
146     const struct fixed31_32 c2 = vpe_fixpt_from_fraction(188515625, 10000000);
147     const struct fixed31_32 c3 = vpe_fixpt_from_fraction(186875, 10000);
148 
149     struct fixed31_32 l_pow_m1;
150     struct fixed31_32 base, div;
151     struct fixed31_32 base2;
152 
153     if (vpe_fixpt_lt(in_x, vpe_fixpt_zero))
154         in_x = vpe_fixpt_zero;
155 
156     if (vpe_fixpt_le(vpe_fixpt_one, in_x)) {
157         *out_y = vpe_fixpt_one;
158         return;
159     }
160 
161     l_pow_m1 = vpe_fixpt_pow(in_x, vpe_fixpt_div(vpe_fixpt_one, m2));
162     base     = vpe_fixpt_sub(l_pow_m1, c1);
163 
164     div = vpe_fixpt_sub(c2, vpe_fixpt_mul(c3, l_pow_m1));
165 
166     base2 = vpe_fixpt_div(base, div);
167     // avoid complex numbers
168     if (vpe_fixpt_lt(base2, vpe_fixpt_zero))
169         base2 = vpe_fixpt_sub(vpe_fixpt_zero, base2);
170 
171     *out_y = vpe_fixpt_pow(base2, vpe_fixpt_div(vpe_fixpt_one, m1));
172 }
173 
174 /* one-time pre-compute PQ values - only for sdr_white_level 80 */
precompute_pq(void)175 static void precompute_pq(void)
176 {
177     int                      i;
178     struct fixed31_32        x;
179     const struct hw_x_point *coord_x        = coordinates_x + 32;
180     struct fixed31_32        scaling_factor = vpe_fixpt_from_fraction(80, 10000);
181 
182     struct fixed31_32 *pq_table = vpe_color_get_table(type_pq_table);
183 
184     /* pow function has problems with arguments too small */
185     for (i = 0; i < 32; i++)
186         pq_table[i] = vpe_fixpt_zero;
187 
188     for (i = 32; i <= MAX_HW_POINTS; i++) {
189         x = vpe_fixpt_mul(coord_x->x, scaling_factor);
190         vpe_compute_pq(x, &pq_table[i]);
191         ++coord_x;
192     }
193 }
194 
195 /* one-time pre-compute dePQ values - only for max pixel value 125 FP16.
196    yuv2rgbScaling is used when the output yuv->rgb is scaled down
197    due to limited range of the yuv2rgb matrix
198 */
199 
precompute_de_pq(struct fixed31_32 x_scale,struct fixed31_32 y_scale)200 static void precompute_de_pq(struct fixed31_32 x_scale, struct fixed31_32 y_scale)
201 {
202     uint32_t           i;
203     struct fixed31_32  y;
204     struct fixed31_32 *de_pq_table = vpe_color_get_table(type_de_pq_table);
205 
206     for (i = 0; i < MAX_HW_POINTS_DEGAMMA; i++) {
207         compute_de_pq(vpe_fixpt_mul(coordinates_x_degamma[i].x, x_scale), &y);
208         de_pq_table[i] = vpe_fixpt_mul(y, y_scale);
209     }
210 }
211 
build_coefficients(struct gamma_coefficients * coefficients,enum color_transfer_func type)212 static bool build_coefficients(
213     struct gamma_coefficients *coefficients, enum color_transfer_func type)
214 {
215 
216     uint32_t i     = 0;
217     uint32_t index = 0;
218     bool     ret   = true;
219 
220     if (type == TRANSFER_FUNC_SRGB)
221         index = 0;
222     else if (type == TRANSFER_FUNC_BT709)
223         index = 1;
224     else if (type == TRANSFER_FUNC_BT1886)
225         index = 3;
226     else {
227         VPE_ASSERT(0);
228         ret = false;
229         goto release;
230     }
231 
232     do {
233         coefficients->a0[i]         = vpe_fixpt_from_fraction(numerator01[index], 10000000);
234         coefficients->a1[i]         = vpe_fixpt_from_fraction(numerator02[index], 1000);
235         coefficients->a2[i]         = vpe_fixpt_from_fraction(numerator03[index], 1000);
236         coefficients->a3[i]         = vpe_fixpt_from_fraction(numerator04[index], 1000);
237         coefficients->user_gamma[i] = vpe_fixpt_from_fraction(numerator05[index], 1000);
238 
239         ++i;
240     } while (i != ARRAY_SIZE(coefficients->a0));
241 release:
242     return ret;
243 }
244 
245 // 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)246 static struct fixed31_32 translate_to_linear_space(struct fixed31_32 arg, struct fixed31_32 a0,
247     struct fixed31_32 a1, struct fixed31_32 a2, struct fixed31_32 a3, struct fixed31_32 gamma)
248 {
249     struct fixed31_32 linear;
250 
251     a0 = vpe_fixpt_mul(a0, a1);
252     if (vpe_fixpt_le(arg, vpe_fixpt_neg(a0)))
253 
254         linear = vpe_fixpt_neg(vpe_fixpt_pow(
255             vpe_fixpt_div(vpe_fixpt_sub(a2, arg), vpe_fixpt_add(vpe_fixpt_one, a3)), gamma));
256 
257     else if (vpe_fixpt_le(vpe_fixpt_neg(a0), arg) && vpe_fixpt_le(arg, a0))
258         linear = vpe_fixpt_div(arg, a1);
259     else
260         linear = vpe_fixpt_pow(
261             vpe_fixpt_div(vpe_fixpt_add(a2, arg), vpe_fixpt_add(vpe_fixpt_one, a3)), gamma);
262 
263     return linear;
264 }
265 
translate_to_linear_space_ex(struct fixed31_32 arg,struct gamma_coefficients * coeff,uint32_t color_index)266 static inline struct fixed31_32 translate_to_linear_space_ex(
267     struct fixed31_32 arg, struct gamma_coefficients *coeff, uint32_t color_index)
268 {
269     if (vpe_fixpt_le(vpe_fixpt_one, arg))
270         return vpe_fixpt_one;
271 
272     return translate_to_linear_space(arg, coeff->a0[color_index], coeff->a1[color_index],
273         coeff->a2[color_index], coeff->a3[color_index], coeff->user_gamma[color_index]);
274 }
275 
translate_from_linear_space(struct translate_from_linear_space_args * args)276 static struct fixed31_32 translate_from_linear_space(struct translate_from_linear_space_args *args)
277 {
278     const struct fixed31_32 one = vpe_fixpt_from_int(1);
279 
280     struct fixed31_32        scratch_1, scratch_2;
281     struct calculate_buffer *cal_buffer = args->cal_buffer;
282 
283     if (vpe_fixpt_le(one, args->arg))
284         return one;
285 
286     if (vpe_fixpt_le(args->arg, vpe_fixpt_neg(args->a0))) {
287         scratch_1 = vpe_fixpt_add(one, args->a3);
288         scratch_2 = vpe_fixpt_pow(vpe_fixpt_neg(args->arg), vpe_fixpt_recip(args->gamma));
289         scratch_1 = vpe_fixpt_mul(scratch_1, scratch_2);
290         scratch_1 = vpe_fixpt_sub(args->a2, scratch_1);
291 
292         return scratch_1;
293     } else if (vpe_fixpt_le(args->a0, args->arg)) {
294         if (cal_buffer->buffer_index == 0) {
295             cal_buffer->gamma_of_2 =
296                 vpe_fixpt_pow(vpe_fixpt_from_int(2), vpe_fixpt_recip(args->gamma));
297         }
298         scratch_1 = vpe_fixpt_add(one, args->a3);
299         // In the first region (first 16 points) and in the
300         // region delimited by START/END we calculate with
301         // full precision to avoid error accumulation.
302         if ((cal_buffer->buffer_index >= PRECISE_LUT_REGION_START &&
303                 cal_buffer->buffer_index <= PRECISE_LUT_REGION_END) ||
304             (cal_buffer->buffer_index < 16))
305             scratch_2 = vpe_fixpt_pow(args->arg, vpe_fixpt_recip(args->gamma));
306         else
307             scratch_2 = vpe_fixpt_mul(
308                 cal_buffer->gamma_of_2, cal_buffer->buffer[cal_buffer->buffer_index % 16]);
309 
310         if (cal_buffer->buffer_index != -1) {
311             cal_buffer->buffer[cal_buffer->buffer_index % 16] = scratch_2;
312             cal_buffer->buffer_index++;
313         }
314 
315         scratch_1 = vpe_fixpt_mul(scratch_1, scratch_2);
316         scratch_1 = vpe_fixpt_sub(scratch_1, args->a2);
317 
318         return scratch_1;
319     } else
320         return vpe_fixpt_mul(args->arg, args->a1);
321 }
322 
translate_from_linear_space_ex(struct fixed31_32 arg,struct gamma_coefficients * coeff,uint32_t color_index,struct calculate_buffer * cal_buffer)323 static struct fixed31_32 translate_from_linear_space_ex(struct fixed31_32 arg,
324     struct gamma_coefficients *coeff, uint32_t color_index, struct calculate_buffer *cal_buffer)
325 {
326     struct translate_from_linear_space_args scratch_gamma_args = {0};
327 
328     scratch_gamma_args.arg        = arg;
329     scratch_gamma_args.a0         = coeff->a0[color_index];
330     scratch_gamma_args.a1         = coeff->a1[color_index];
331     scratch_gamma_args.a2         = coeff->a2[color_index];
332     scratch_gamma_args.a3         = coeff->a3[color_index];
333     scratch_gamma_args.gamma      = coeff->user_gamma[color_index];
334     scratch_gamma_args.cal_buffer = cal_buffer;
335 
336     return translate_from_linear_space(&scratch_gamma_args);
337 }
338 
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)339 static void build_pq(uint32_t hw_points_num, const struct hw_x_point *coordinate_x,
340     struct fixed31_32 x_scale, struct fixed31_32 y_scale, struct pwl_float_data_ex *rgb_regamma)
341 {
342     uint32_t i, curve_start_index;
343 
344     struct pwl_float_data_ex *rgb     = rgb_regamma;
345     const struct hw_x_point  *coord_x = coordinate_x;
346     struct fixed31_32         output;
347     struct fixed31_32         slope;
348 
349     /* Curve Start index is from segment 2^-24, the first segment must be
350      * treated as a linear interpolation due to numbers being to small for power
351      * operations
352      */
353     curve_start_index = 32;
354     vpe_compute_pq(vpe_fixpt_mul(coord_x[curve_start_index].x, x_scale), &output);
355     output = vpe_fixpt_mul(output, y_scale);
356     slope = vpe_fixpt_div(output, coord_x[curve_start_index].x);
357 
358     for (i = 0; i < curve_start_index; i++) {
359         output = vpe_fixpt_mul(coord_x->x, slope);
360         rgb->r = output;
361         rgb->g = output;
362         rgb->b = output;
363 
364         ++coord_x;
365         ++rgb;
366     }
367 
368     for (i = curve_start_index; i <= hw_points_num; i++) {
369 
370         vpe_compute_pq(vpe_fixpt_mul(coord_x->x, x_scale), &output);
371         output = vpe_fixpt_mul(output, y_scale);
372         rgb->r = output;
373         rgb->g = output;
374         rgb->b = output;
375 
376         ++coord_x;
377         ++rgb;
378     }
379 }
380 
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)381 static void build_de_pq(uint32_t hw_points_num, const struct hw_x_point *coordinate_x_degamma,
382     struct fixed31_32 x_scale, struct fixed31_32 y_scale,
383     struct transfer_func_distributed_points *de_pq)
384 {
385     struct fixed31_32  output;
386 
387     for (uint32_t i = 0; i < hw_points_num; i++) {
388         compute_de_pq(vpe_fixpt_mul(coordinates_x_degamma[i].x, x_scale), &output);
389         output = vpe_fixpt_mul(output, y_scale);
390         de_pq->red[i]   = output;
391         de_pq->green[i] = output;
392         de_pq->blue[i]  = output;
393     }
394 }
395 
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)396 static bool build_degamma(uint32_t hw_points_num, const struct hw_x_point *coordinate_x_degamma,
397     enum color_transfer_func type, struct fixed31_32 x_scale, struct fixed31_32 y_scale,
398     struct transfer_func_distributed_points *curve)
399 {
400     uint32_t                  i;
401     struct gamma_coefficients coeff;
402     struct fixed31_32         output;
403     bool                      ret = false;
404 
405     if (!build_coefficients(&coeff, type))
406         goto release;
407 
408     /* De-gamma X is 2^-8 to 2^0 i.e. 9 regions
409      */
410 
411     i = 0;
412     while (i != MAX_HW_POINTS_DEGAMMA) {
413         output = vpe_fixpt_mul(coordinate_x_degamma[i].x, x_scale);
414 
415         output = translate_to_linear_space_ex(output, &coeff, 0);
416         output = vpe_fixpt_mul(output, y_scale);
417 
418         curve->red[i]   = output;
419         curve->green[i] = output;
420         curve->blue[i]  = output;
421         i++;
422     }
423     ret = true;
424 release:
425     return ret;
426 }
427 
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)428 static bool build_regamma(struct vpe_priv *vpe_priv, uint32_t hw_points_num,
429     const struct hw_x_point *coordinate_x, enum color_transfer_func type, struct fixed31_32 x_scale,
430     struct fixed31_32 y_scale, struct calculate_buffer *cal_buffer,
431     struct pwl_float_data_ex *rgb_regamma)
432 {
433     uint32_t i;
434     bool     ret = false;
435 
436     struct gamma_coefficients *coeff;
437     struct pwl_float_data_ex  *rgb     = rgb_regamma;
438     const struct hw_x_point   *coord_x = coordinate_x;
439 
440     coeff = (struct gamma_coefficients *)vpe_zalloc(sizeof(*coeff));
441     if (!coeff)
442         goto release;
443 
444     if (!build_coefficients(coeff, type))
445         goto release;
446 
447     memset(cal_buffer->buffer, 0, NUM_PTS_IN_REGION * sizeof(struct fixed31_32));
448     cal_buffer->buffer_index = 0; // see variable definition for more info
449 
450     i = 0;
451     while (i <= hw_points_num) {
452         /* TODO use y vs r,g,b */
453         rgb->r = vpe_fixpt_mul(coord_x->x, x_scale);
454         rgb->r = translate_from_linear_space_ex(rgb->r, coeff, 0, cal_buffer);
455         rgb->r = vpe_fixpt_mul(rgb->r, y_scale);
456         rgb->g = rgb->r;
457         rgb->b = rgb->r;
458         ++coord_x;
459         ++rgb;
460         ++i;
461     }
462     cal_buffer->buffer_index = -1;
463     ret                      = true;
464 release:
465     vpe_free(coeff);
466     return ret;
467 }
468 
build_new_custom_resulted_curve(uint32_t hw_points_num,struct transfer_func_distributed_points * tf_pts)469 static void build_new_custom_resulted_curve(
470     uint32_t hw_points_num, struct transfer_func_distributed_points *tf_pts)
471 {
472     uint32_t i = 0;
473 
474     while (i != hw_points_num + 1) {
475         tf_pts->red[i]   = vpe_fixpt_clamp(tf_pts->red[i], vpe_fixpt_zero, vpe_fixpt_one);
476         tf_pts->green[i] = vpe_fixpt_clamp(tf_pts->green[i], vpe_fixpt_zero, vpe_fixpt_one);
477         tf_pts->blue[i]  = vpe_fixpt_clamp(tf_pts->blue[i], vpe_fixpt_zero, vpe_fixpt_one);
478 
479         ++i;
480     }
481 }
482 
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)483 static bool map_regamma_hw_to_x_user(struct hw_x_point *coords_x, const struct pwl_float_data_ex *rgb_regamma,
484     uint32_t hw_points_num, struct transfer_func_distributed_points *tf_pts, bool doClamping)
485 {
486     /* setup to spare calculated ideal regamma values */
487 
488     uint32_t                        i       = 0;
489     struct hw_x_point              *coords  = coords_x;
490     const struct pwl_float_data_ex *regamma = rgb_regamma;
491 
492     /* just copy current rgb_regamma into  tf_pts */
493     while (i <= hw_points_num) {
494         tf_pts->red[i]   = regamma->r;
495         tf_pts->green[i] = regamma->g;
496         tf_pts->blue[i]  = regamma->b;
497 
498         ++regamma;
499         ++i;
500     }
501 
502     if (doClamping) {
503         /* this should be named differently, all it does is clamp to 0-1 */
504         build_new_custom_resulted_curve(hw_points_num, tf_pts);
505     }
506 
507     return true;
508 }
509 
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)510 static bool calculate_curve(struct vpe_priv *vpe_priv, enum color_transfer_func trans,
511     struct fixed31_32 x_scale, struct fixed31_32 y_scale,
512     struct transfer_func_distributed_points *points, struct pwl_float_data_ex *rgb_regamma,
513     struct calculate_buffer *cal_buffer)
514 {
515     int                                      hdr_norm = vpe_priv->resource.internal_hdr_normalization;
516     struct fixed31_32                        combined_scale;
517 
518     bool ret = false;
519     switch (trans)
520     {
521     case TRANSFER_FUNC_SRGB:
522     case TRANSFER_FUNC_BT709:
523     case TRANSFER_FUNC_BT1886:
524         build_regamma(vpe_priv, MAX_HW_POINTS, coordinates_x, trans, x_scale, y_scale, cal_buffer,
525             rgb_regamma);
526         ret = true;
527         break;
528     case TRANSFER_FUNC_PQ2084:
529         build_pq(MAX_HW_POINTS, coordinates_x, x_scale, y_scale, rgb_regamma);
530         ret = true;
531         break;
532     case TRANSFER_FUNC_LINEAR:
533         combined_scale = vpe_fixpt_div_int(vpe_fixpt_one, hdr_norm);
534         combined_scale = vpe_fixpt_mul(combined_scale,  y_scale);
535         combined_scale = vpe_fixpt_mul(combined_scale, x_scale);
536         for (int i = 0; i < MAX_HW_POINTS; i++) {
537             rgb_regamma[i].r = vpe_fixpt_mul(coordinates_x[i].x, combined_scale);
538             rgb_regamma[i].g = rgb_regamma[i].r;
539             rgb_regamma[i].b = rgb_regamma[i].r;
540         }
541 
542         ret = true;
543         break;
544     case TRANSFER_FUNC_NORMALIZED_PQ:
545     case TRANSFER_FUNC_UNKNOWN:
546         break;
547     default:
548         break;
549     }
550 
551     return ret;
552 }
553 
554 #define _EXTRA_POINTS 3
555 
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)556 bool vpe_color_calculate_degamma_params(struct vpe_priv *vpe_priv, struct fixed31_32 x_scale,
557     struct fixed31_32 y_scale, struct transfer_func *input_tf)
558 {
559     struct transfer_func_distributed_points *tf_pts   = &input_tf->tf_pts;
560     enum color_transfer_func                 tf       = input_tf->tf;
561     int                                      hdr_norm = vpe_priv->resource.internal_hdr_normalization;
562     bool                                     ret      = false;
563     struct fixed31_32                        scale_combined;
564     struct fixed31_32                        output;
565 
566 
567 
568     switch (tf)
569     {
570     case TRANSFER_FUNC_PQ2084:
571     case TRANSFER_FUNC_NORMALIZED_PQ:
572         build_de_pq(MAX_HW_POINTS_DEGAMMA, coordinates_x_degamma, x_scale, y_scale, tf_pts);
573         ret = true;
574         break;
575     case TRANSFER_FUNC_SRGB:
576     case TRANSFER_FUNC_BT709:
577     case TRANSFER_FUNC_BT1886:
578         build_degamma(MAX_HW_POINTS_DEGAMMA, coordinates_x_degamma, tf, x_scale, y_scale, tf_pts);
579         ret = true;
580         break;
581     case TRANSFER_FUNC_LINEAR:
582         scale_combined = vpe_fixpt_mul(vpe_fixpt_from_int(hdr_norm), x_scale);
583         scale_combined = vpe_fixpt_mul(scale_combined, y_scale);
584 
585         for (int i = 0; i < MAX_HW_POINTS_DEGAMMA; i ++) {
586             output = vpe_fixpt_mul(coordinates_x_degamma[i].x, scale_combined);
587             tf_pts->red[i] = output;
588             tf_pts->green[i] = output;
589             tf_pts->blue[i] = output;
590         }
591         ret = true;
592         break;
593     default:
594         break;
595     }
596     return ret;
597 }
598 
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)599 bool vpe_color_calculate_regamma_params(struct vpe_priv *vpe_priv, struct fixed31_32 x_scale,
600     struct fixed31_32 y_scale, struct calculate_buffer *cal_buffer, struct transfer_func *output_tf)
601 {
602     struct transfer_func_distributed_points *tf_pts      = &output_tf->tf_pts;
603     struct pwl_float_data_ex                *rgb_regamma = NULL;
604     struct pixel_gamma_point                *coeff       = NULL;
605     enum color_transfer_func                 tf;
606     bool                                     ret = false;
607 
608     rgb_regamma = (struct pwl_float_data_ex *)vpe_zalloc(
609         (MAX_HW_POINTS + _EXTRA_POINTS) * sizeof(*rgb_regamma));
610     if (!rgb_regamma)
611         goto rgb_regamma_alloc_fail;
612 
613     coeff =
614         (struct pixel_gamma_point *)vpe_zalloc((MAX_HW_POINTS + _EXTRA_POINTS) * sizeof(*coeff));
615     if (!coeff)
616         goto coeff_alloc_fail;
617 
618     tf = output_tf->tf;
619 
620     ret = calculate_curve(vpe_priv, tf, x_scale, y_scale, tf_pts, rgb_regamma, cal_buffer);
621 
622     if (ret) {
623         map_regamma_hw_to_x_user(coordinates_x, rgb_regamma, MAX_HW_POINTS, tf_pts, false);
624     }
625 
626     vpe_free(coeff);
627 coeff_alloc_fail:
628     vpe_free(rgb_regamma);
629 rgb_regamma_alloc_fail:
630     return ret;
631 }
632