• 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 "shaper_builder.h"
26 #include "custom_fp16.h"
27 #include "fixed31_32.h"
28 #include "color.h"
29 #include "color_gamma.h"
30 
31 struct shaper_setup_out {
32     int exp_begin_raw;
33     int exp_end_raw;
34     int begin_custom_1_6_12;
35     int end_custom_0_6_10;
36     int end_base_fixed_0_14;
37 };
38 
vpe_computer_shaper_pq_14u(double x,struct fixed31_32 normalized_factor)39 static unsigned int vpe_computer_shaper_pq_14u(double x, struct fixed31_32 normalized_factor)
40 {
41     unsigned          output_fixpt_14u = 0x3fff;
42     struct fixed31_32 x_fixpt          = vpe_fixpt_one;
43     struct fixed31_32 output_fixpt;
44 
45     if (x < 1.0) {
46         // Convert double -> fixpt31_32
47         x_fixpt.value =
48             vpe_double_to_fixed_point(x, (unsigned long long)0, (unsigned long long)32, true);
49 
50         // Linear -> PQ
51         vpe_compute_pq(x_fixpt, &output_fixpt);
52 
53         // PQ -> Normalized PQ
54         output_fixpt = vpe_fixpt_div(output_fixpt, normalized_factor);
55 
56         // fixpt31_32 -> fixpt14u
57         output_fixpt_14u = vpe_fixpt_clamp_u0d14(output_fixpt);
58     }
59 
60     return output_fixpt_14u; // Max 14u Value
61 }
calculate_shaper_properties_const_hdr_mult(const struct vpe_shaper_setup_in * shaper_in,struct shaper_setup_out * shaper_out)62 static bool calculate_shaper_properties_const_hdr_mult(
63     const struct vpe_shaper_setup_in *shaper_in, struct shaper_setup_out *shaper_out)
64 {
65     double                          x;
66     struct vpe_custom_float_format2 fmt;
67     struct vpe_custom_float_value2  custom_float;
68     int                             num_exp;
69 
70     bool   ret     = false;
71     int    isize   = 1 << 14;
72     double divider = isize - 1;
73     double x_double_begin;
74 
75     double multiplyer = shaper_in->source_luminance / 10000.0 * shaper_in->shaper_in_max;
76 
77     fmt.flags.Uint      = 0;
78     fmt.flags.bits.sign = 1;
79     fmt.mantissaBits    = 12;
80     fmt.exponentaBits   = 6;
81 
82     x = pow(1.0 / divider, 2.2) * multiplyer;
83     if (!vpe_convert_to_custom_float_ex_generic(x, &fmt, &custom_float))
84         goto release;
85     shaper_out->exp_begin_raw = custom_float.exponenta;
86 
87     if (!vpe_from_1_6_12_to_double(false, custom_float.exponenta, 0, &x_double_begin))
88         goto release;
89 
90     if (!vpe_convert_to_custom_float_generic(
91             x_double_begin, &fmt, &shaper_out->begin_custom_1_6_12))
92         goto release;
93 
94     fmt.flags.bits.sign = 0;
95     fmt.mantissaBits    = 10;
96     if (!vpe_convert_to_custom_float_ex_generic(multiplyer, &fmt, &custom_float))
97         goto release;
98     shaper_out->exp_end_raw = custom_float.exponenta;
99     if (!vpe_convert_to_custom_float_generic(multiplyer, &fmt, &shaper_out->end_custom_0_6_10))
100         goto release;
101     shaper_out->end_base_fixed_0_14 = isize - 1;
102     num_exp                         = shaper_out->exp_end_raw - shaper_out->exp_begin_raw + 1;
103     if (num_exp > 34)
104         goto release;
105     ret = true;
106 release:
107     return ret;
108 }
109 
calculate_shaper_properties_variable_hdr_mult(const struct vpe_shaper_setup_in * shaper_in,struct shaper_setup_out * shaper_out)110 static bool calculate_shaper_properties_variable_hdr_mult(
111     const struct vpe_shaper_setup_in *shaper_in, struct shaper_setup_out *shaper_out)
112 {
113     struct vpe_custom_float_format2 fmt;
114     struct vpe_custom_float_value2  custom_float;
115     int                             num_exp;
116 
117     bool   ret            = false;
118     int    isize          = 1 << 14;
119     double divider        = isize - 1;
120     double x_double_begin = 0;
121 
122     fmt.flags.Uint    = 0;
123     fmt.exponentaBits = 6;
124     fmt.mantissaBits  = 10;
125     if (!vpe_convert_to_custom_float_ex_generic(shaper_in->shaper_in_max, &fmt, &custom_float))
126         goto release;
127 
128     if (!vpe_convert_to_custom_float_generic(
129             shaper_in->shaper_in_max, &fmt, &shaper_out->end_custom_0_6_10))
130         goto release;
131 
132     shaper_out->exp_end_raw   = custom_float.exponenta;
133     shaper_out->exp_begin_raw = shaper_out->exp_end_raw - 33;
134 
135     shaper_out->end_base_fixed_0_14 = isize - 1;
136 
137     if (!vpe_from_1_6_12_to_double(false, shaper_out->exp_begin_raw, 0, &x_double_begin))
138         goto release;
139 
140     fmt.mantissaBits    = 12;
141     fmt.flags.bits.sign = 1;
142 
143     if (!vpe_convert_to_custom_float_generic(
144             x_double_begin, &fmt, &shaper_out->begin_custom_1_6_12))
145         goto release;
146 
147     num_exp = shaper_out->exp_end_raw - shaper_out->exp_begin_raw + 1;
148     if (num_exp > 34)
149         goto release;
150     ret = true;
151 release:
152     return ret;
153 }
154 
build_shaper_2_2_segments_distribution(int num_regions,int * arr_segments)155 static int build_shaper_2_2_segments_distribution(int num_regions, int *arr_segments)
156 {
157     int       i;
158     int       counter;
159     int       num_segments                = 0;
160     int       num_segments_total          = 0;
161     const int proposed_2_2_distribution[] = {5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 2, 2, 1, 1, 1, 0, 0,
162         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
163     int proposed_regions = ARRAY_SIZE(proposed_2_2_distribution);
164 
165     if (proposed_regions < num_regions)
166         goto release;
167     counter = 0;
168 
169     for (i = num_regions - 1; i >= 0; i--) {
170         arr_segments[counter] = proposed_2_2_distribution[i];
171         num_segments += 1 << proposed_2_2_distribution[i];
172         counter++;
173     }
174 release:
175     return num_segments;
176 }
177 
vpe_build_shaper(const struct vpe_shaper_setup_in * shaper_in,enum color_transfer_func shaper_tf,struct fixed31_32 pq_norm_gain,struct pwl_params * shaper_out)178 enum vpe_status vpe_build_shaper(const struct vpe_shaper_setup_in *shaper_in,
179     enum color_transfer_func shaper_tf, struct fixed31_32 pq_norm_gain,
180     struct pwl_params *shaper_out)
181 {
182     enum vpe_status ret = VPE_STATUS_ERROR;
183 
184     int                     num_points = 0;
185     int                     arr_regions[34];
186     struct shaper_setup_out shaper_params;
187     int                     i, j;
188     int                     num_exp;
189 
190     unsigned int exp;
191     double       x, delta_segments;
192     int          lut_counter = 0;
193     int          segments_current;
194     int          segments_offset;
195 
196     unsigned int decimalBits = 14;
197 
198     unsigned int mask    = (1 << decimalBits) - 1;
199     double       d_norm  = mask;
200     double       divider = shaper_in->shaper_in_max;
201 
202     unsigned int output_fixpt_14u;
203 
204     struct fixed31_32 normalized_factor = vpe_fixpt_one;
205 
206     if (shaper_tf == TRANSFER_FUNC_NORMALIZED_PQ) {
207         struct fixed31_32 normalized_gain = vpe_fixpt_one;
208 
209         normalized_gain = vpe_fixpt_div_int(pq_norm_gain, HDR_PEAK_WHITE);
210         vpe_compute_pq(normalized_gain, &normalized_factor);
211     }
212 
213     if (shaper_in->use_const_hdr_mult &&
214         !calculate_shaper_properties_const_hdr_mult(shaper_in, &shaper_params))
215         goto release;
216     else if (!calculate_shaper_properties_variable_hdr_mult(shaper_in, &shaper_params))
217         goto release;
218 
219     exp = shaper_params.exp_begin_raw;
220 
221     num_exp    = shaper_params.exp_end_raw - shaper_params.exp_begin_raw + 1;
222     num_points = build_shaper_2_2_segments_distribution(num_exp, arr_regions);
223 
224     segments_offset = 0;
225 
226     for (i = 0; i < num_exp; i++) {
227         segments_current                         = 1 << arr_regions[i];
228         shaper_out->arr_curve_points[i].segments_num = arr_regions[i];
229         shaper_out->arr_curve_points[i].offset       = segments_offset;
230         segments_offset                          = segments_offset + segments_current;
231         if (!vpe_from_1_6_12_to_double(false, exp, 0, &x))
232             goto release;
233         x /= divider;
234         delta_segments = x / segments_current;
235 
236         for (j = 0; j < segments_current; j++) {
237             switch (shaper_tf) {
238             case TRANSFER_FUNC_NORMALIZED_PQ:
239                 if (i > 2) {
240                     output_fixpt_14u = vpe_computer_shaper_pq_14u(x, normalized_factor);
241                 } else {
242                     output_fixpt_14u = vpe_to_fixed_point(decimalBits, x, mask, d_norm);
243                 }
244                 break;
245             case TRANSFER_FUNC_LINEAR:
246             default:
247                 output_fixpt_14u = vpe_to_fixed_point(decimalBits, x, mask, d_norm);
248                 break;
249             }
250             shaper_out->rgb_resulted[lut_counter].red_reg = output_fixpt_14u;
251             shaper_out->rgb_resulted[lut_counter].green_reg =
252                 shaper_out->rgb_resulted[lut_counter].red_reg;
253             shaper_out->rgb_resulted[lut_counter].blue_reg =
254                 shaper_out->rgb_resulted[lut_counter].red_reg;
255 
256             x += delta_segments;
257             lut_counter++;
258         }
259         exp++;
260     }
261 
262     shaper_out->corner_points[0].red.custom_float_x = shaper_params.begin_custom_1_6_12;
263     shaper_out->corner_points[0].green.custom_float_x =
264         shaper_out->corner_points[0].red.custom_float_x;
265     shaper_out->corner_points[0].blue.custom_float_x =
266         shaper_out->corner_points[0].red.custom_float_x;
267 
268     shaper_out->corner_points[1].red.custom_float_x = shaper_params.end_custom_0_6_10;
269     shaper_out->corner_points[1].green.custom_float_x =
270         shaper_out->corner_points[1].red.custom_float_x;
271     shaper_out->corner_points[1].blue.custom_float_x =
272         shaper_out->corner_points[1].red.custom_float_x;
273 
274     shaper_out->corner_points[1].red.custom_float_y = shaper_params.end_base_fixed_0_14;
275     shaper_out->corner_points[1].green.custom_float_y =
276         shaper_out->corner_points[1].red.custom_float_y;
277     shaper_out->corner_points[1].blue.custom_float_y =
278         shaper_out->corner_points[1].red.custom_float_y;
279 
280     for (i = 1; i < num_points; i++) {
281         shaper_out->rgb_resulted[i - 1].delta_red_reg =
282             shaper_out->rgb_resulted[i].red_reg - shaper_out->rgb_resulted[i - 1].red_reg;
283         shaper_out->rgb_resulted[i - 1].delta_green_reg =
284             shaper_out->rgb_resulted[i - 1].delta_red_reg;
285         shaper_out->rgb_resulted[i - 1].delta_blue_reg =
286             shaper_out->rgb_resulted[i - 1].delta_red_reg;
287     }
288 
289     shaper_out->hw_points_num = num_points;
290     ret                   = VPE_STATUS_OK;
291 
292 release:
293     return ret;
294 }
295