1 | /* |
2 | * Copyright 2016 Advanced Micro Devices, Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
22 | * Authors: AMD |
23 | * |
24 | */ |
25 | #include "dc.h" |
26 | #include "reg_helper.h" |
27 | #include "dcn10_dpp.h" |
28 | |
29 | #include "dcn10_cm_common.h" |
30 | #include "custom_float.h" |
31 | |
32 | #define REG(reg) reg |
33 | |
34 | #define CTX \ |
35 | ctx |
36 | |
37 | #undef FN |
38 | #define FN(reg_name, field_name) \ |
39 | reg->shifts.field_name, reg->masks.field_name |
40 | |
41 | void cm_helper_program_color_matrices( |
42 | struct dc_context *ctx, |
43 | const uint16_t *regval, |
44 | const struct color_matrices_reg *reg) |
45 | { |
46 | uint32_t cur_csc_reg; |
47 | unsigned int i = 0; |
48 | |
49 | for (cur_csc_reg = reg->csc_c11_c12; |
50 | cur_csc_reg <= reg->csc_c33_c34; |
51 | cur_csc_reg++) { |
52 | |
53 | const uint16_t *regval0 = &(regval[2 * i]); |
54 | const uint16_t *regval1 = &(regval[(2 * i) + 1]); |
55 | |
56 | REG_SET_2(cur_csc_reg, 0, |
57 | csc_c11, *regval0, |
58 | csc_c12, *regval1); |
59 | |
60 | i++; |
61 | } |
62 | |
63 | } |
64 | |
65 | void cm_helper_program_xfer_func( |
66 | struct dc_context *ctx, |
67 | const struct pwl_params *params, |
68 | const struct xfer_func_reg *reg) |
69 | { |
70 | uint32_t reg_region_cur; |
71 | unsigned int i = 0; |
72 | |
73 | REG_SET_2(reg->start_cntl_b, 0, |
74 | exp_region_start, params->corner_points[0].blue.custom_float_x, |
75 | exp_resion_start_segment, 0); |
76 | REG_SET_2(reg->start_cntl_g, 0, |
77 | exp_region_start, params->corner_points[0].green.custom_float_x, |
78 | exp_resion_start_segment, 0); |
79 | REG_SET_2(reg->start_cntl_r, 0, |
80 | exp_region_start, params->corner_points[0].red.custom_float_x, |
81 | exp_resion_start_segment, 0); |
82 | |
83 | REG_SET(reg->start_slope_cntl_b, 0, |
84 | field_region_linear_slope, params->corner_points[0].blue.custom_float_slope); |
85 | REG_SET(reg->start_slope_cntl_g, 0, |
86 | field_region_linear_slope, params->corner_points[0].green.custom_float_slope); |
87 | REG_SET(reg->start_slope_cntl_r, 0, |
88 | field_region_linear_slope, params->corner_points[0].red.custom_float_slope); |
89 | |
90 | REG_SET(reg->start_end_cntl1_b, 0, |
91 | field_region_end, params->corner_points[1].blue.custom_float_x); |
92 | REG_SET_2(reg->start_end_cntl2_b, 0, |
93 | field_region_end_slope, params->corner_points[1].blue.custom_float_slope, |
94 | field_region_end_base, params->corner_points[1].blue.custom_float_y); |
95 | |
96 | REG_SET(reg->start_end_cntl1_g, 0, |
97 | field_region_end, params->corner_points[1].green.custom_float_x); |
98 | REG_SET_2(reg->start_end_cntl2_g, 0, |
99 | field_region_end_slope, params->corner_points[1].green.custom_float_slope, |
100 | field_region_end_base, params->corner_points[1].green.custom_float_y); |
101 | |
102 | REG_SET(reg->start_end_cntl1_r, 0, |
103 | field_region_end, params->corner_points[1].red.custom_float_x); |
104 | REG_SET_2(reg->start_end_cntl2_r, 0, |
105 | field_region_end_slope, params->corner_points[1].red.custom_float_slope, |
106 | field_region_end_base, params->corner_points[1].red.custom_float_y); |
107 | |
108 | for (reg_region_cur = reg->region_start; |
109 | reg_region_cur <= reg->region_end; |
110 | reg_region_cur++) { |
111 | |
112 | const struct gamma_curve *curve0 = &(params->arr_curve_points[2 * i]); |
113 | const struct gamma_curve *curve1 = &(params->arr_curve_points[(2 * i) + 1]); |
114 | |
115 | REG_SET_4(reg_region_cur, 0, |
116 | exp_region0_lut_offset, curve0->offset, |
117 | exp_region0_num_segments, curve0->segments_num, |
118 | exp_region1_lut_offset, curve1->offset, |
119 | exp_region1_num_segments, curve1->segments_num); |
120 | |
121 | i++; |
122 | } |
123 | |
124 | } |
125 | |
126 | |
127 | |
128 | bool cm_helper_convert_to_custom_float( |
129 | struct pwl_result_data *rgb_resulted, |
130 | struct curve_points3 *corner_points, |
131 | uint32_t hw_points_num, |
132 | bool fixpoint) |
133 | { |
134 | struct custom_float_format fmt; |
135 | |
136 | struct pwl_result_data *rgb = rgb_resulted; |
137 | |
138 | uint32_t i = 0; |
139 | |
140 | fmt.exponenta_bits = 6; |
141 | fmt.mantissa_bits = 12; |
142 | fmt.sign = false; |
143 | |
144 | /* corner_points[0] - beginning base, slope offset for R,G,B |
145 | * corner_points[1] - end base, slope offset for R,G,B |
146 | */ |
147 | if (!convert_to_custom_float_format(value: corner_points[0].red.x, format: &fmt, |
148 | result: &corner_points[0].red.custom_float_x)) { |
149 | BREAK_TO_DEBUGGER(); |
150 | return false; |
151 | } |
152 | if (!convert_to_custom_float_format(value: corner_points[0].green.x, format: &fmt, |
153 | result: &corner_points[0].green.custom_float_x)) { |
154 | BREAK_TO_DEBUGGER(); |
155 | return false; |
156 | } |
157 | if (!convert_to_custom_float_format(value: corner_points[0].blue.x, format: &fmt, |
158 | result: &corner_points[0].blue.custom_float_x)) { |
159 | BREAK_TO_DEBUGGER(); |
160 | return false; |
161 | } |
162 | |
163 | if (!convert_to_custom_float_format(value: corner_points[0].red.offset, format: &fmt, |
164 | result: &corner_points[0].red.custom_float_offset)) { |
165 | BREAK_TO_DEBUGGER(); |
166 | return false; |
167 | } |
168 | if (!convert_to_custom_float_format(value: corner_points[0].green.offset, format: &fmt, |
169 | result: &corner_points[0].green.custom_float_offset)) { |
170 | BREAK_TO_DEBUGGER(); |
171 | return false; |
172 | } |
173 | if (!convert_to_custom_float_format(value: corner_points[0].blue.offset, format: &fmt, |
174 | result: &corner_points[0].blue.custom_float_offset)) { |
175 | BREAK_TO_DEBUGGER(); |
176 | return false; |
177 | } |
178 | |
179 | if (!convert_to_custom_float_format(value: corner_points[0].red.slope, format: &fmt, |
180 | result: &corner_points[0].red.custom_float_slope)) { |
181 | BREAK_TO_DEBUGGER(); |
182 | return false; |
183 | } |
184 | if (!convert_to_custom_float_format(value: corner_points[0].green.slope, format: &fmt, |
185 | result: &corner_points[0].green.custom_float_slope)) { |
186 | BREAK_TO_DEBUGGER(); |
187 | return false; |
188 | } |
189 | if (!convert_to_custom_float_format(value: corner_points[0].blue.slope, format: &fmt, |
190 | result: &corner_points[0].blue.custom_float_slope)) { |
191 | BREAK_TO_DEBUGGER(); |
192 | return false; |
193 | } |
194 | |
195 | fmt.mantissa_bits = 10; |
196 | fmt.sign = false; |
197 | |
198 | if (!convert_to_custom_float_format(value: corner_points[1].red.x, format: &fmt, |
199 | result: &corner_points[1].red.custom_float_x)) { |
200 | BREAK_TO_DEBUGGER(); |
201 | return false; |
202 | } |
203 | if (!convert_to_custom_float_format(value: corner_points[1].green.x, format: &fmt, |
204 | result: &corner_points[1].green.custom_float_x)) { |
205 | BREAK_TO_DEBUGGER(); |
206 | return false; |
207 | } |
208 | if (!convert_to_custom_float_format(value: corner_points[1].blue.x, format: &fmt, |
209 | result: &corner_points[1].blue.custom_float_x)) { |
210 | BREAK_TO_DEBUGGER(); |
211 | return false; |
212 | } |
213 | |
214 | if (fixpoint == true) { |
215 | corner_points[1].red.custom_float_y = |
216 | dc_fixpt_clamp_u0d14(arg: corner_points[1].red.y); |
217 | corner_points[1].green.custom_float_y = |
218 | dc_fixpt_clamp_u0d14(arg: corner_points[1].green.y); |
219 | corner_points[1].blue.custom_float_y = |
220 | dc_fixpt_clamp_u0d14(arg: corner_points[1].blue.y); |
221 | } else { |
222 | if (!convert_to_custom_float_format(value: corner_points[1].red.y, |
223 | format: &fmt, result: &corner_points[1].red.custom_float_y)) { |
224 | BREAK_TO_DEBUGGER(); |
225 | return false; |
226 | } |
227 | if (!convert_to_custom_float_format(value: corner_points[1].green.y, |
228 | format: &fmt, result: &corner_points[1].green.custom_float_y)) { |
229 | BREAK_TO_DEBUGGER(); |
230 | return false; |
231 | } |
232 | if (!convert_to_custom_float_format(value: corner_points[1].blue.y, |
233 | format: &fmt, result: &corner_points[1].blue.custom_float_y)) { |
234 | BREAK_TO_DEBUGGER(); |
235 | return false; |
236 | } |
237 | } |
238 | |
239 | if (!convert_to_custom_float_format(value: corner_points[1].red.slope, format: &fmt, |
240 | result: &corner_points[1].red.custom_float_slope)) { |
241 | BREAK_TO_DEBUGGER(); |
242 | return false; |
243 | } |
244 | if (!convert_to_custom_float_format(value: corner_points[1].green.slope, format: &fmt, |
245 | result: &corner_points[1].green.custom_float_slope)) { |
246 | BREAK_TO_DEBUGGER(); |
247 | return false; |
248 | } |
249 | if (!convert_to_custom_float_format(value: corner_points[1].blue.slope, format: &fmt, |
250 | result: &corner_points[1].blue.custom_float_slope)) { |
251 | BREAK_TO_DEBUGGER(); |
252 | return false; |
253 | } |
254 | |
255 | if (hw_points_num == 0 || rgb_resulted == NULL || fixpoint == true) |
256 | return true; |
257 | |
258 | fmt.mantissa_bits = 12; |
259 | fmt.sign = true; |
260 | |
261 | while (i != hw_points_num) { |
262 | if (!convert_to_custom_float_format(value: rgb->red, format: &fmt, |
263 | result: &rgb->red_reg)) { |
264 | BREAK_TO_DEBUGGER(); |
265 | return false; |
266 | } |
267 | |
268 | if (!convert_to_custom_float_format(value: rgb->green, format: &fmt, |
269 | result: &rgb->green_reg)) { |
270 | BREAK_TO_DEBUGGER(); |
271 | return false; |
272 | } |
273 | |
274 | if (!convert_to_custom_float_format(value: rgb->blue, format: &fmt, |
275 | result: &rgb->blue_reg)) { |
276 | BREAK_TO_DEBUGGER(); |
277 | return false; |
278 | } |
279 | |
280 | if (!convert_to_custom_float_format(value: rgb->delta_red, format: &fmt, |
281 | result: &rgb->delta_red_reg)) { |
282 | BREAK_TO_DEBUGGER(); |
283 | return false; |
284 | } |
285 | |
286 | if (!convert_to_custom_float_format(value: rgb->delta_green, format: &fmt, |
287 | result: &rgb->delta_green_reg)) { |
288 | BREAK_TO_DEBUGGER(); |
289 | return false; |
290 | } |
291 | |
292 | if (!convert_to_custom_float_format(value: rgb->delta_blue, format: &fmt, |
293 | result: &rgb->delta_blue_reg)) { |
294 | BREAK_TO_DEBUGGER(); |
295 | return false; |
296 | } |
297 | |
298 | ++rgb; |
299 | ++i; |
300 | } |
301 | |
302 | return true; |
303 | } |
304 | |
305 | /* driver uses 32 regions or less, but DCN HW has 34, extra 2 are set to 0 */ |
306 | #define MAX_REGIONS_NUMBER 34 |
307 | #define MAX_LOW_POINT 25 |
308 | #define NUMBER_REGIONS 32 |
309 | #define NUMBER_SW_SEGMENTS 16 |
310 | |
311 | #define DC_LOGGER \ |
312 | ctx->logger |
313 | |
314 | bool cm_helper_translate_curve_to_hw_format(struct dc_context *ctx, |
315 | const struct dc_transfer_func *output_tf, |
316 | struct pwl_params *lut_params, bool fixpoint) |
317 | { |
318 | struct curve_points3 *corner_points; |
319 | struct pwl_result_data *rgb_resulted; |
320 | struct pwl_result_data *rgb; |
321 | struct pwl_result_data *rgb_plus_1; |
322 | struct pwl_result_data *rgb_minus_1; |
323 | |
324 | int32_t region_start, region_end; |
325 | int32_t i; |
326 | uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points; |
327 | |
328 | if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) |
329 | return false; |
330 | |
331 | corner_points = lut_params->corner_points; |
332 | rgb_resulted = lut_params->rgb_resulted; |
333 | hw_points = 0; |
334 | |
335 | memset(lut_params, 0, sizeof(struct pwl_params)); |
336 | memset(seg_distr, 0, sizeof(seg_distr)); |
337 | |
338 | if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22) { |
339 | /* 32 segments |
340 | * segments are from 2^-25 to 2^7 |
341 | */ |
342 | for (i = 0; i < NUMBER_REGIONS ; i++) |
343 | seg_distr[i] = 3; |
344 | |
345 | region_start = -MAX_LOW_POINT; |
346 | region_end = NUMBER_REGIONS - MAX_LOW_POINT; |
347 | } else { |
348 | /* 11 segments |
349 | * segment is from 2^-10 to 2^1 |
350 | * There are less than 256 points, for optimization |
351 | */ |
352 | seg_distr[0] = 3; |
353 | seg_distr[1] = 4; |
354 | seg_distr[2] = 4; |
355 | seg_distr[3] = 4; |
356 | seg_distr[4] = 4; |
357 | seg_distr[5] = 4; |
358 | seg_distr[6] = 4; |
359 | seg_distr[7] = 4; |
360 | seg_distr[8] = 4; |
361 | seg_distr[9] = 4; |
362 | seg_distr[10] = 1; |
363 | |
364 | region_start = -10; |
365 | region_end = 1; |
366 | } |
367 | |
368 | for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) |
369 | seg_distr[i] = -1; |
370 | |
371 | for (k = 0; k < MAX_REGIONS_NUMBER; k++) { |
372 | if (seg_distr[k] != -1) |
373 | hw_points += (1 << seg_distr[k]); |
374 | } |
375 | |
376 | j = 0; |
377 | for (k = 0; k < (region_end - region_start); k++) { |
378 | increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); |
379 | start_index = (region_start + k + MAX_LOW_POINT) * |
380 | NUMBER_SW_SEGMENTS; |
381 | for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; |
382 | i += increment) { |
383 | if (j == hw_points - 1) |
384 | break; |
385 | rgb_resulted[j].red = output_tf->tf_pts.red[i]; |
386 | rgb_resulted[j].green = output_tf->tf_pts.green[i]; |
387 | rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; |
388 | j++; |
389 | } |
390 | } |
391 | |
392 | /* last point */ |
393 | start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; |
394 | rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; |
395 | rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; |
396 | rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; |
397 | |
398 | rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red; |
399 | rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green; |
400 | rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue; |
401 | |
402 | // All 3 color channels have same x |
403 | corner_points[0].red.x = dc_fixpt_pow(arg1: dc_fixpt_from_int(arg: 2), |
404 | arg2: dc_fixpt_from_int(arg: region_start)); |
405 | corner_points[0].green.x = corner_points[0].red.x; |
406 | corner_points[0].blue.x = corner_points[0].red.x; |
407 | |
408 | corner_points[1].red.x = dc_fixpt_pow(arg1: dc_fixpt_from_int(arg: 2), |
409 | arg2: dc_fixpt_from_int(arg: region_end)); |
410 | corner_points[1].green.x = corner_points[1].red.x; |
411 | corner_points[1].blue.x = corner_points[1].red.x; |
412 | |
413 | corner_points[0].red.y = rgb_resulted[0].red; |
414 | corner_points[0].green.y = rgb_resulted[0].green; |
415 | corner_points[0].blue.y = rgb_resulted[0].blue; |
416 | |
417 | corner_points[0].red.slope = dc_fixpt_div(arg1: corner_points[0].red.y, |
418 | arg2: corner_points[0].red.x); |
419 | corner_points[0].green.slope = dc_fixpt_div(arg1: corner_points[0].green.y, |
420 | arg2: corner_points[0].green.x); |
421 | corner_points[0].blue.slope = dc_fixpt_div(arg1: corner_points[0].blue.y, |
422 | arg2: corner_points[0].blue.x); |
423 | |
424 | /* see comment above, m_arrPoints[1].y should be the Y value for the |
425 | * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) |
426 | */ |
427 | corner_points[1].red.y = rgb_resulted[hw_points - 1].red; |
428 | corner_points[1].green.y = rgb_resulted[hw_points - 1].green; |
429 | corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue; |
430 | corner_points[1].red.slope = dc_fixpt_zero; |
431 | corner_points[1].green.slope = dc_fixpt_zero; |
432 | corner_points[1].blue.slope = dc_fixpt_zero; |
433 | |
434 | if (output_tf->tf == TRANSFER_FUNCTION_PQ) { |
435 | /* for PQ, we want to have a straight line from last HW X point, |
436 | * and the slope to be such that we hit 1.0 at 10000 nits. |
437 | */ |
438 | const struct fixed31_32 end_value = |
439 | dc_fixpt_from_int(arg: 125); |
440 | |
441 | corner_points[1].red.slope = dc_fixpt_div( |
442 | arg1: dc_fixpt_sub(arg1: dc_fixpt_one, arg2: corner_points[1].red.y), |
443 | arg2: dc_fixpt_sub(arg1: end_value, arg2: corner_points[1].red.x)); |
444 | corner_points[1].green.slope = dc_fixpt_div( |
445 | arg1: dc_fixpt_sub(arg1: dc_fixpt_one, arg2: corner_points[1].green.y), |
446 | arg2: dc_fixpt_sub(arg1: end_value, arg2: corner_points[1].green.x)); |
447 | corner_points[1].blue.slope = dc_fixpt_div( |
448 | arg1: dc_fixpt_sub(arg1: dc_fixpt_one, arg2: corner_points[1].blue.y), |
449 | arg2: dc_fixpt_sub(arg1: end_value, arg2: corner_points[1].blue.x)); |
450 | } |
451 | |
452 | lut_params->hw_points_num = hw_points; |
453 | |
454 | k = 0; |
455 | for (i = 1; i < MAX_REGIONS_NUMBER; i++) { |
456 | if (seg_distr[k] != -1) { |
457 | lut_params->arr_curve_points[k].segments_num = |
458 | seg_distr[k]; |
459 | lut_params->arr_curve_points[i].offset = |
460 | lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]); |
461 | } |
462 | k++; |
463 | } |
464 | |
465 | if (seg_distr[k] != -1) |
466 | lut_params->arr_curve_points[k].segments_num = seg_distr[k]; |
467 | |
468 | rgb = rgb_resulted; |
469 | rgb_plus_1 = rgb_resulted + 1; |
470 | rgb_minus_1 = rgb; |
471 | |
472 | i = 1; |
473 | while (i != hw_points + 1) { |
474 | |
475 | if (i >= hw_points - 1) { |
476 | if (dc_fixpt_lt(arg1: rgb_plus_1->red, arg2: rgb->red)) |
477 | rgb_plus_1->red = dc_fixpt_add(arg1: rgb->red, arg2: rgb_minus_1->delta_red); |
478 | if (dc_fixpt_lt(arg1: rgb_plus_1->green, arg2: rgb->green)) |
479 | rgb_plus_1->green = dc_fixpt_add(arg1: rgb->green, arg2: rgb_minus_1->delta_green); |
480 | if (dc_fixpt_lt(arg1: rgb_plus_1->blue, arg2: rgb->blue)) |
481 | rgb_plus_1->blue = dc_fixpt_add(arg1: rgb->blue, arg2: rgb_minus_1->delta_blue); |
482 | } |
483 | |
484 | rgb->delta_red = dc_fixpt_sub(arg1: rgb_plus_1->red, arg2: rgb->red); |
485 | rgb->delta_green = dc_fixpt_sub(arg1: rgb_plus_1->green, arg2: rgb->green); |
486 | rgb->delta_blue = dc_fixpt_sub(arg1: rgb_plus_1->blue, arg2: rgb->blue); |
487 | |
488 | |
489 | if (fixpoint == true) { |
490 | uint32_t red_clamp = dc_fixpt_clamp_u0d14(arg: rgb->delta_red); |
491 | uint32_t green_clamp = dc_fixpt_clamp_u0d14(arg: rgb->delta_green); |
492 | uint32_t blue_clamp = dc_fixpt_clamp_u0d14(arg: rgb->delta_blue); |
493 | |
494 | if (red_clamp >> 10 || green_clamp >> 10 || blue_clamp >> 10) |
495 | DC_LOG_WARNING("Losing delta precision while programming shaper LUT." ); |
496 | |
497 | rgb->delta_red_reg = red_clamp & 0x3ff; |
498 | rgb->delta_green_reg = green_clamp & 0x3ff; |
499 | rgb->delta_blue_reg = blue_clamp & 0x3ff; |
500 | rgb->red_reg = dc_fixpt_clamp_u0d14(arg: rgb->red); |
501 | rgb->green_reg = dc_fixpt_clamp_u0d14(arg: rgb->green); |
502 | rgb->blue_reg = dc_fixpt_clamp_u0d14(arg: rgb->blue); |
503 | } |
504 | |
505 | ++rgb_plus_1; |
506 | rgb_minus_1 = rgb; |
507 | ++rgb; |
508 | ++i; |
509 | } |
510 | cm_helper_convert_to_custom_float(rgb_resulted, |
511 | corner_points: lut_params->corner_points, |
512 | hw_points_num: hw_points, fixpoint); |
513 | |
514 | return true; |
515 | } |
516 | |
517 | #define NUM_DEGAMMA_REGIONS 12 |
518 | |
519 | |
520 | bool cm_helper_translate_curve_to_degamma_hw_format( |
521 | const struct dc_transfer_func *output_tf, |
522 | struct pwl_params *lut_params) |
523 | { |
524 | struct curve_points3 *corner_points; |
525 | struct pwl_result_data *rgb_resulted; |
526 | struct pwl_result_data *rgb; |
527 | struct pwl_result_data *rgb_plus_1; |
528 | |
529 | int32_t region_start, region_end; |
530 | int32_t i; |
531 | uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points; |
532 | |
533 | if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) |
534 | return false; |
535 | |
536 | corner_points = lut_params->corner_points; |
537 | rgb_resulted = lut_params->rgb_resulted; |
538 | hw_points = 0; |
539 | |
540 | memset(lut_params, 0, sizeof(struct pwl_params)); |
541 | memset(seg_distr, 0, sizeof(seg_distr)); |
542 | |
543 | region_start = -NUM_DEGAMMA_REGIONS; |
544 | region_end = 0; |
545 | |
546 | |
547 | for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) |
548 | seg_distr[i] = -1; |
549 | /* 12 segments |
550 | * segments are from 2^-12 to 0 |
551 | */ |
552 | for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++) |
553 | seg_distr[i] = 4; |
554 | |
555 | for (k = 0; k < MAX_REGIONS_NUMBER; k++) { |
556 | if (seg_distr[k] != -1) |
557 | hw_points += (1 << seg_distr[k]); |
558 | } |
559 | |
560 | j = 0; |
561 | for (k = 0; k < (region_end - region_start); k++) { |
562 | increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); |
563 | start_index = (region_start + k + MAX_LOW_POINT) * |
564 | NUMBER_SW_SEGMENTS; |
565 | for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; |
566 | i += increment) { |
567 | if (j == hw_points - 1) |
568 | break; |
569 | rgb_resulted[j].red = output_tf->tf_pts.red[i]; |
570 | rgb_resulted[j].green = output_tf->tf_pts.green[i]; |
571 | rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; |
572 | j++; |
573 | } |
574 | } |
575 | |
576 | /* last point */ |
577 | start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; |
578 | rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; |
579 | rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; |
580 | rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; |
581 | |
582 | rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red; |
583 | rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green; |
584 | rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue; |
585 | |
586 | corner_points[0].red.x = dc_fixpt_pow(arg1: dc_fixpt_from_int(arg: 2), |
587 | arg2: dc_fixpt_from_int(arg: region_start)); |
588 | corner_points[0].green.x = corner_points[0].red.x; |
589 | corner_points[0].blue.x = corner_points[0].red.x; |
590 | corner_points[1].red.x = dc_fixpt_pow(arg1: dc_fixpt_from_int(arg: 2), |
591 | arg2: dc_fixpt_from_int(arg: region_end)); |
592 | corner_points[1].green.x = corner_points[1].red.x; |
593 | corner_points[1].blue.x = corner_points[1].red.x; |
594 | |
595 | corner_points[0].red.y = rgb_resulted[0].red; |
596 | corner_points[0].green.y = rgb_resulted[0].green; |
597 | corner_points[0].blue.y = rgb_resulted[0].blue; |
598 | |
599 | /* see comment above, m_arrPoints[1].y should be the Y value for the |
600 | * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) |
601 | */ |
602 | corner_points[1].red.y = rgb_resulted[hw_points - 1].red; |
603 | corner_points[1].green.y = rgb_resulted[hw_points - 1].green; |
604 | corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue; |
605 | corner_points[1].red.slope = dc_fixpt_zero; |
606 | corner_points[1].green.slope = dc_fixpt_zero; |
607 | corner_points[1].blue.slope = dc_fixpt_zero; |
608 | |
609 | if (output_tf->tf == TRANSFER_FUNCTION_PQ) { |
610 | /* for PQ, we want to have a straight line from last HW X point, |
611 | * and the slope to be such that we hit 1.0 at 10000 nits. |
612 | */ |
613 | const struct fixed31_32 end_value = |
614 | dc_fixpt_from_int(arg: 125); |
615 | |
616 | corner_points[1].red.slope = dc_fixpt_div( |
617 | arg1: dc_fixpt_sub(arg1: dc_fixpt_one, arg2: corner_points[1].red.y), |
618 | arg2: dc_fixpt_sub(arg1: end_value, arg2: corner_points[1].red.x)); |
619 | corner_points[1].green.slope = dc_fixpt_div( |
620 | arg1: dc_fixpt_sub(arg1: dc_fixpt_one, arg2: corner_points[1].green.y), |
621 | arg2: dc_fixpt_sub(arg1: end_value, arg2: corner_points[1].green.x)); |
622 | corner_points[1].blue.slope = dc_fixpt_div( |
623 | arg1: dc_fixpt_sub(arg1: dc_fixpt_one, arg2: corner_points[1].blue.y), |
624 | arg2: dc_fixpt_sub(arg1: end_value, arg2: corner_points[1].blue.x)); |
625 | } |
626 | |
627 | lut_params->hw_points_num = hw_points; |
628 | |
629 | k = 0; |
630 | for (i = 1; i < MAX_REGIONS_NUMBER; i++) { |
631 | if (seg_distr[k] != -1) { |
632 | lut_params->arr_curve_points[k].segments_num = |
633 | seg_distr[k]; |
634 | lut_params->arr_curve_points[i].offset = |
635 | lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]); |
636 | } |
637 | k++; |
638 | } |
639 | |
640 | if (seg_distr[k] != -1) |
641 | lut_params->arr_curve_points[k].segments_num = seg_distr[k]; |
642 | |
643 | rgb = rgb_resulted; |
644 | rgb_plus_1 = rgb_resulted + 1; |
645 | |
646 | i = 1; |
647 | while (i != hw_points + 1) { |
648 | rgb->delta_red = dc_fixpt_sub(arg1: rgb_plus_1->red, arg2: rgb->red); |
649 | rgb->delta_green = dc_fixpt_sub(arg1: rgb_plus_1->green, arg2: rgb->green); |
650 | rgb->delta_blue = dc_fixpt_sub(arg1: rgb_plus_1->blue, arg2: rgb->blue); |
651 | |
652 | ++rgb_plus_1; |
653 | ++rgb; |
654 | ++i; |
655 | } |
656 | cm_helper_convert_to_custom_float(rgb_resulted, |
657 | corner_points: lut_params->corner_points, |
658 | hw_points_num: hw_points, fixpoint: false); |
659 | |
660 | return true; |
661 | } |
662 | |