• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2022-2024 Advanced Micro Devices, Inc. All rights reserved.
2 
3 #include <string.h>
4 #include <math.h>
5 #include "color_bg.h"
6 #include "vpe_priv.h"
7 
8 struct csc_vector {
9     float x;
10     float y;
11     float z;
12 };
13 
14 struct csc_table {
15     struct csc_vector rgb_offset; // RGB offset
16     struct csc_vector red_coef;   // RED coefficient
17     struct csc_vector green_coef; // GREEN coefficient
18     struct csc_vector blue_coef;  // BLUE coefficient
19 };
20 
21 
22 const double bt_709_rgb_xyz_matrix[] = {
23     0.135676572958501,   0.117645247657296,   0.059378179384203,
24     0.069958232931727,   0.235290495314592,   0.023751271753681,
25     0.006359839357430,   0.039215082552432,   0.312725078090138
26 };
27 
28 const double bt_601_rgb_xyz_matrix[] = {
29     0.129468377303939,   0.120169907240092,   0.063061715455969,
30     0.069871822671967,   0.230648692928563,   0.028479484399470,
31     0.006165160823997,   0.036826261896157,   0.315308577279846
32 };
33 
34 const double bt_2020_rgb_xyz_matrix[] = {
35     0.209559197891125,   0.047578961279863,   0.055561840829013,
36     0.086428369751707,   0.223061365529709,   0.019510264718585,
37     0.000000000000000,   0.009235916013150,   0.349064083986850
38 };
39 
40 const double bt_709_xyz_rgb_matrix[] = {
41     9.850972467794900,    -4.672897196261683,    -1.515534225814599,
42    -2.946029289607537,     5.702028879962675,     0.126307165371354,
43     0.169088388136759,    -0.619990756501448,     3.212679374598414
44 };
45 
46 const double bt_601_xyz_rgb_matrix[] = {
47     10.656544932293809,   -5.288117709127149,    -1.653672548215019,
48    -3.249384680406732,     6.011485965740993,     0.106904010143450,
49     0.171144655726832,    -0.598710197023623,     3.191344462670923
50 };
51 
52 const double bt_2020_xyz_rgb_matrix[] = {
53     5.217784765870115,    -1.081066212086299,    -0.770110277731489,
54    -2.026396206177778,     4.913316828677627,     0.047928710680581,
55     0.053616587979668,    -0.130001864005497,     2.863535322904176
56 };
57 
58 static struct csc_table bgcolor_to_rgbfull_table[COLOR_SPACE_MAX] = {
59     [COLOR_SPACE_YCBCR601] =
60         {
61             {0.0f, -0.5f, -0.5f},
62             {1.0f, 0.0f, 1.402f},
63             {1.0f, -0.344136286f, -0.714136286f},
64             {1.0f, 1.772f, 0.0f},
65         },
66     [COLOR_SPACE_YCBCR709] =
67         {
68             {0.0f, -0.5f, -0.5f},
69             {1.0f, 0.0f, 1.5748f},
70             {1.0f, -0.187324273f, -0.468124273f},
71             {1.0f, 1.8556f, 0.0f},
72         },
73     [COLOR_SPACE_YCBCR601_LIMITED] =
74         {
75             {-0.0625f, -0.5f, -0.5f},
76             {1.164383562f, 0.0f, 1.596026786f},
77             {1.164383562f, -0.39176229f, -0.812967647f},
78             {1.164383562f, 2.017232143f, 0.0f},
79         },
80     [COLOR_SPACE_YCBCR709_LIMITED] =
81         {
82             {-0.0625f, -0.5f, -0.5f},
83             {1.164383562f, 0.0f, 1.792741071f},
84             {1.164383562f, -0.213248614f, -0.532909329f},
85             {1.164383562f, 2.112401786f, 0.0f},
86         },
87     [COLOR_SPACE_2020_YCBCR] =
88         {
89             {0.0f, -512.f / 1023.f, -512.f / 1023.f},
90             {1.0f, 0.0f, 1.4746f},
91             {1.0f, -0.164553127f, -0.571353127f},
92             {1.0f, 1.8814f, 0.0f},
93         },
94     [COLOR_SPACE_2020_YCBCR_LIMITED] =
95         {
96             {-0.0625f, -0.5f, -0.5f},
97             {1.167808219f, 0.0f, 1.683611384f},
98             {1.167808219f, -0.187877063f, -0.652337331f},
99             {1.167808219f, 2.148071652f, 0.0f},
100         },
101     [COLOR_SPACE_SRGB_LIMITED] =
102         {
103             {-0.0626221f, -0.0626221f, -0.0626221f},
104             {1.167783652f, 0.0f, 0.0f},
105             {0.0f, 1.167783652f, 0.0f},
106             {0.0f, 0.0, 1.167783652f},
107         },
108     [COLOR_SPACE_2020_RGB_LIMITEDRANGE] = {
109         {-0.0626221f, -0.0626221f, -0.0626221f},
110         {1.167783652f, 0.0f, 0.0f},
111         {0.0f, 1.167783652f, 0.0f},
112         {0.0f, 0.0, 1.167783652f},
113     }};
114 
clip_double(double x)115 static double clip_double(double x)
116 {
117     if (x < 0.0)
118         return 0.0;
119     else if (x > 1.0)
120         return 1.0;
121     else
122         return x;
123 }
124 
clip_float(float x)125 static float clip_float(float x)
126 {
127     if (x < 0.0f)
128         return 0.0f;
129     else if (x > 1.0f)
130         return 1.0f;
131     else
132         return x;
133 }
134 
color_multiply_matrices_double(double * mResult,double * M1,double * M2,unsigned int Rows1,unsigned int Cols1,unsigned int Cols2)135 static void color_multiply_matrices_double(double *mResult, double *M1,
136     double *M2, unsigned int Rows1, unsigned int Cols1, unsigned int Cols2)
137 {
138     unsigned int i, j, k;
139 
140     for (i = 0; i < Rows1; i++) {
141         for (j = 0; j < Cols2; j++) {
142             mResult[(i * Cols2) + j] = 0.0;
143             for (k = 0; k < Cols1; k++)
144                 mResult[(i * Cols2) + j] = mResult[(i * Cols2) + j] +
145                     M1[(i * Cols1) + k] * M2[(k * Cols2) + j];
146         }
147     }
148 }
149 
set_gamut_remap_matrix(double * res,enum color_space src_cs,enum color_space dst_cs)150 static void set_gamut_remap_matrix(double* res, enum color_space src_cs, enum color_space dst_cs) {
151 
152     double rgb_to_xyz[9] = { 0.0 };
153     double xyz_to_rgb[9] = { 0.0 };
154 
155     switch (src_cs)
156     {
157     case COLOR_SPACE_SRGB:
158     case COLOR_SPACE_SRGB_LIMITED:
159     case COLOR_SPACE_MSREF_SCRGB:
160     case COLOR_SPACE_YCBCR709_LIMITED:
161     case COLOR_SPACE_YCBCR709:
162     case COLOR_SPACE_YCBCR_JFIF:
163     case COLOR_SPACE_RGB_JFIF:
164         memcpy(rgb_to_xyz, bt_709_rgb_xyz_matrix, 9 * sizeof(double));
165         break;
166     case COLOR_SPACE_YCBCR601:
167     case COLOR_SPACE_YCBCR601_LIMITED:
168         memcpy(rgb_to_xyz, bt_601_rgb_xyz_matrix, 9 * sizeof(double));
169         break;
170     case COLOR_SPACE_2020_RGB_FULLRANGE:
171     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
172     case COLOR_SPACE_2020_YCBCR:
173     case COLOR_SPACE_2020_YCBCR_LIMITED:
174         memcpy(rgb_to_xyz, bt_2020_rgb_xyz_matrix, 9 * sizeof(double));
175         break;
176     default:
177         VPE_ASSERT(0);
178         break;
179     }
180 
181     switch (dst_cs)
182     {
183     case COLOR_SPACE_SRGB:
184     case COLOR_SPACE_SRGB_LIMITED:
185     case COLOR_SPACE_MSREF_SCRGB:
186     case COLOR_SPACE_YCBCR709_LIMITED:
187     case COLOR_SPACE_YCBCR709:
188     case COLOR_SPACE_YCBCR_JFIF:
189     case COLOR_SPACE_RGB_JFIF:
190         memcpy(xyz_to_rgb, bt_709_xyz_rgb_matrix, 9 * sizeof(double));
191         break;
192     case COLOR_SPACE_YCBCR601:
193     case COLOR_SPACE_YCBCR601_LIMITED:
194         memcpy(xyz_to_rgb, bt_601_xyz_rgb_matrix, 9 * sizeof(double));
195         break;
196     case COLOR_SPACE_2020_RGB_FULLRANGE:
197     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
198     case COLOR_SPACE_2020_YCBCR:
199     case COLOR_SPACE_2020_YCBCR_LIMITED:
200         memcpy(xyz_to_rgb, bt_2020_xyz_rgb_matrix, 9 * sizeof(double));
201         break;
202     default:
203         VPE_ASSERT(0);
204         break;
205     }
206 
207     color_multiply_matrices_double(res, xyz_to_rgb, rgb_to_xyz, 3, 3, 3);
208 
209 }
210 
vpe_bg_csc(struct vpe_color * bg_color,enum color_space cs)211 bool vpe_bg_csc(struct vpe_color *bg_color, enum color_space cs)
212 {
213     struct csc_table *entry             = &bgcolor_to_rgbfull_table[cs];
214     float             csc_final[3]      = {0};
215     float             csc_mm[3][4]      = {0};
216     bool              output_is_clipped = false;
217 
218     memcpy(&csc_mm[0][0], &entry->red_coef, sizeof(struct csc_vector));
219     memcpy(&csc_mm[1][0], &entry->green_coef, sizeof(struct csc_vector));
220     memcpy(&csc_mm[2][0], &entry->blue_coef, sizeof(struct csc_vector));
221 
222     csc_mm[0][3] = entry->rgb_offset.x * csc_mm[0][0] + entry->rgb_offset.y * csc_mm[0][1] +
223                    entry->rgb_offset.z * csc_mm[0][2];
224 
225     csc_mm[1][3] = entry->rgb_offset.x * csc_mm[1][0] + entry->rgb_offset.y * csc_mm[1][1] +
226                    entry->rgb_offset.z * csc_mm[1][2];
227 
228     csc_mm[2][3] = entry->rgb_offset.x * csc_mm[2][0] + entry->rgb_offset.y * csc_mm[2][1] +
229                    entry->rgb_offset.z * csc_mm[2][2];
230 
231     csc_final[0] = csc_mm[0][0] * bg_color->ycbcra.y + csc_mm[0][1] * bg_color->ycbcra.cb +
232                    csc_mm[0][2] * bg_color->ycbcra.cr + csc_mm[0][3];
233 
234     csc_final[1] = csc_mm[1][0] * bg_color->ycbcra.y + csc_mm[1][1] * bg_color->ycbcra.cb +
235                    csc_mm[1][2] * bg_color->ycbcra.cr + csc_mm[1][3];
236 
237     csc_final[2] = csc_mm[2][0] * bg_color->ycbcra.y + csc_mm[2][1] * bg_color->ycbcra.cb +
238                    csc_mm[2][2] * bg_color->ycbcra.cr + csc_mm[2][3];
239 
240     // switch to RGB components
241     bg_color->rgba.a = bg_color->ycbcra.a;
242     bg_color->rgba.r = clip_float(csc_final[0]);
243     bg_color->rgba.g = clip_float(csc_final[1]);
244     bg_color->rgba.b = clip_float(csc_final[2]);
245     if ((bg_color->rgba.r != csc_final[0]) || (bg_color->rgba.g != csc_final[1]) ||
246         (bg_color->rgba.b != csc_final[2])) {
247         output_is_clipped = true;
248     }
249     bg_color->is_ycbcr = false;
250     return output_is_clipped;
251 }
252 
vpe_is_global_bg_blend_applied(struct stream_ctx * stream_ctx)253 bool vpe_is_global_bg_blend_applied(struct stream_ctx *stream_ctx)
254 {
255 
256     return (stream_ctx->stream.blend_info.blending)  &&
257         (stream_ctx->stream.blend_info.global_alpha) &&
258         (stream_ctx->stream.blend_info.global_alpha_value != 1.0);
259 }
260 
261 struct gamma_coefs {
262     float a0;
263     float a1;
264     float a2;
265     float a3;
266     float user_gamma;
267     float user_contrast;
268     float user_brightness;
269 };
270 
271 // srgb, 709, G24
272 static const int32_t numerator01[] = {31308, 180000, 0};
273 static const int32_t numerator02[] = {12920, 4500, 0};
274 static const int32_t numerator03[] = {55, 99, 0};
275 static const int32_t numerator04[] = {55, 99, 0};
276 static const int32_t numerator05[] = {2400, 2222, 2400};
277 
build_coefficients(struct gamma_coefs * coefficients,enum color_transfer_func type)278 static bool build_coefficients(struct gamma_coefs *coefficients, enum color_transfer_func type)
279 {
280     uint32_t index = 0;
281     bool     ret   = true;
282 
283     if (type == TRANSFER_FUNC_SRGB)
284         index = 0;
285     else if (type == TRANSFER_FUNC_BT709)
286         index = 1;
287     else if (type == TRANSFER_FUNC_BT1886)
288         index = 2;
289     else {
290         ret = false;
291         goto release;
292     }
293 
294     coefficients->a0         = (float)numerator01[index] / 10000000.0f;
295     coefficients->a1         = (float)numerator02[index] / 1000.0f;
296     coefficients->a2         = (float)numerator03[index] / 1000.0f;
297     coefficients->a3         = (float)numerator04[index] / 1000.0f;
298     coefficients->user_gamma = (float)numerator05[index] / 1000.0f;
299 
300 release:
301     return ret;
302 }
303 
translate_to_linear_space(double arg,double a0,double a1,double a2,double a3,double gamma)304 static double translate_to_linear_space(
305     double arg, double a0, double a1, double a2, double a3, double gamma)
306 {
307     double linear;
308     double base;
309 
310     a0 *= a1;
311     if (arg <= -a0) {
312         base   = (a2 - arg) / (1.0 + a3);
313         linear = -pow(base, gamma);
314     } else if ((-a0 <= arg) && (arg <= a0))
315         linear = arg / a1;
316     else {
317         base   = (a2 + arg) / (1.0 + a3);
318         linear = pow(base, gamma);
319     }
320 
321     return linear;
322 }
323 
324 // for 709 & sRGB
compute_degam(enum color_transfer_func tf,double inY,double * outX,bool clip)325 static void compute_degam(enum color_transfer_func tf, double inY, double *outX, bool clip)
326 {
327     double             ret;
328     struct gamma_coefs coefs = {0};
329 
330     build_coefficients(&coefs, tf);
331 
332     ret = translate_to_linear_space(inY, (double)coefs.a0, (double)coefs.a1, (double)coefs.a2,
333         (double)coefs.a3, (double)coefs.user_gamma);
334 
335     if (clip) {
336         ret = clip_double(ret);
337     }
338     *outX = ret;
339 }
340 
get_maximum_fp(double a,double b)341 static double get_maximum_fp(double a, double b)
342 {
343     if (a > b)
344         return a;
345     return b;
346 }
347 
compute_depq(double inY,double * outX,bool clip)348 static void compute_depq(double inY, double *outX, bool clip)
349 {
350     double M1 = 0.159301758;
351     double M2 = 78.84375;
352     double C1 = 0.8359375;
353     double C2 = 18.8515625;
354     double C3 = 18.6875;
355 
356     double nPowM2;
357     double base;
358     double one      = 1.0;
359     double zero     = 0.0;
360     bool   negative = false;
361     double ret;
362 
363     if (inY < zero) {
364         inY      = -inY;
365         negative = true;
366     }
367     nPowM2 = pow(inY, one / M2);
368     base   = get_maximum_fp(nPowM2 - C1, zero) / (C2 - C3 * nPowM2);
369     ret    = pow(base, one / M1);
370     if (clip) {
371         ret = clip_double(ret);
372     }
373     if (negative)
374         ret = -ret;
375 
376     *outX = ret;
377 }
378 
is_limited_cs(enum color_space cs)379 static bool is_limited_cs(enum color_space cs)
380 {
381     bool is_limited = false;
382 
383     switch (cs)
384     {
385     case COLOR_SPACE_SRGB:
386     case COLOR_SPACE_2020_RGB_FULLRANGE:
387     case COLOR_SPACE_MSREF_SCRGB:
388     case COLOR_SPACE_YCBCR601:
389     case COLOR_SPACE_YCBCR709:
390     case COLOR_SPACE_YCBCR_JFIF:
391     case COLOR_SPACE_RGB_JFIF:
392     case COLOR_SPACE_2020_YCBCR:
393         is_limited = false;
394         break;
395     case COLOR_SPACE_SRGB_LIMITED:
396     case COLOR_SPACE_YCBCR601_LIMITED:
397     case COLOR_SPACE_YCBCR709_LIMITED:
398     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
399     case COLOR_SPACE_2020_YCBCR_LIMITED:
400         is_limited = true;
401         break;
402     default:
403         VPE_ASSERT(0);
404         is_limited = false;
405         break;
406     }
407     return is_limited;
408 }
409 
vpe_bg_degam(struct transfer_func * output_tf,struct vpe_color * bg_color)410 static void vpe_bg_degam(
411     struct transfer_func *output_tf, struct vpe_color *bg_color) {
412 
413     double degam_r = (double)bg_color->rgba.r;
414     double degam_g = (double)bg_color->rgba.g;
415     double degam_b = (double)bg_color->rgba.b;
416 
417     // de-gam
418     switch (output_tf->tf) {
419 
420     case TRANSFER_FUNC_PQ2084:
421         compute_depq((double)bg_color->rgba.r, &degam_r, true);
422         compute_depq((double)bg_color->rgba.g, &degam_g, true);
423         compute_depq((double)bg_color->rgba.b, &degam_b, true);
424         break;
425     case TRANSFER_FUNC_SRGB:
426     case TRANSFER_FUNC_BT709:
427     case TRANSFER_FUNC_BT1886:
428         compute_degam(output_tf->tf, (double)bg_color->rgba.r, &degam_r, true);
429         compute_degam(output_tf->tf, (double)bg_color->rgba.g, &degam_g, true);
430         compute_degam(output_tf->tf, (double)bg_color->rgba.b, &degam_b, true);
431         break;
432     case TRANSFER_FUNC_LINEAR:
433         break;
434     default:
435         VPE_ASSERT(0);
436         break;
437     }
438     bg_color->rgba.r = (float)degam_r;
439     bg_color->rgba.g = (float)degam_g;
440     bg_color->rgba.b = (float)degam_b;
441 
442 }
443 
vpe_bg_inverse_gamut_remap(enum color_space output_cs,struct transfer_func * output_tf,struct vpe_color * bg_color)444 static void vpe_bg_inverse_gamut_remap(enum color_space output_cs,
445     struct transfer_func *output_tf, struct vpe_color *bg_color)
446 {
447 
448         double bg_rgb[3] = { 0.0 };
449         double final_bg_rgb[3] = { 0.0 };
450         double matrix[9] = { 0.0 };
451         bg_rgb[0] = (double)bg_color->rgba.r;
452         bg_rgb[1] = (double)bg_color->rgba.g;
453         bg_rgb[2] = (double)bg_color->rgba.b;
454 
455         switch (output_tf->tf) {
456         case TRANSFER_FUNC_LINEAR:
457             /* Since linear output uses Bt709, and this conversion is only needed
458              * when the tone mapping is enabled on (Bt2020) input, it is needed to
459              * apply the reverse of Bt2020 -> Bt709 on the background color to
460              * cancel out the effect of Bt2020 -> Bt709 on the background color.
461              */
462             set_gamut_remap_matrix(matrix, COLOR_SPACE_SRGB, COLOR_SPACE_2020_RGB_FULLRANGE);
463             color_multiply_matrices_double(final_bg_rgb, matrix, bg_rgb, 3, 3, 1);
464 
465             bg_color->rgba.r = (float)clip_double(final_bg_rgb[0]);
466             bg_color->rgba.g = (float)clip_double(final_bg_rgb[1]);
467             bg_color->rgba.b = (float)clip_double(final_bg_rgb[2]);
468 
469             break;
470         case TRANSFER_FUNC_PQ2084:
471         case TRANSFER_FUNC_SRGB:
472         case TRANSFER_FUNC_BT709:
473         case TRANSFER_FUNC_BT1886:
474             break;
475         default:
476             VPE_ASSERT(0);
477             break;
478         }
479 
480 }
481 
482 // To understand the logic for background color conversion,
483 // please refer to vpe_update_output_gamma_sequence in color.c
vpe_bg_color_convert(enum color_space output_cs,struct transfer_func * output_tf,enum vpe_surface_pixel_format pixel_format,struct vpe_color * mpc_bg_color,struct vpe_color * opp_bg_color,bool enable_3dlut)484 void vpe_bg_color_convert(enum color_space output_cs, struct transfer_func *output_tf,
485     enum vpe_surface_pixel_format pixel_format, struct vpe_color *mpc_bg_color,
486     struct vpe_color *opp_bg_color, bool enable_3dlut)
487 {
488     if (output_tf->type != TF_TYPE_BYPASS) {
489         // inverse degam
490         if (output_tf->tf == TRANSFER_FUNC_PQ2084 && !is_limited_cs(output_cs))
491             vpe_bg_degam(output_tf, mpc_bg_color);
492         // inverse gamut remap
493         if (enable_3dlut)
494             vpe_bg_inverse_gamut_remap(output_cs, output_tf, mpc_bg_color);
495     }
496     // for TF_TYPE_BYPASS, bg color should be programmed to mpc as linear
497 }
498