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