• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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