xref: /aosp_15_r20/external/mesa3d/src/amd/vpelib/src/core/color_bg.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 #include <string.h>
2 #include <math.h>
3 #include "color_bg.h"
4 #include "vpe_priv.h"
5 
6 struct csc_vector {
7     float x;
8     float y;
9     float z;
10 };
11 
12 struct csc_table {
13     struct csc_vector rgb_offset; // RGB offset
14     struct csc_vector red_coef;   // RED coefficient
15     struct csc_vector green_coef; // GREEN coefficient
16     struct csc_vector blue_coef;  // BLUE coefficient
17 };
18 
19 
20 const double bt_709_rgb_xyz_matrix[] = {
21     0.135676572958501,   0.117645247657296,   0.059378179384203,
22     0.069958232931727,   0.235290495314592,   0.023751271753681,
23     0.006359839357430,   0.039215082552432,   0.312725078090138
24 };
25 
26 const double bt_601_rgb_xyz_matrix[] = {
27     0.129468377303939,   0.120169907240092,   0.063061715455969,
28     0.069871822671967,   0.230648692928563,   0.028479484399470,
29     0.006165160823997,   0.036826261896157,   0.315308577279846
30 };
31 
32 const double bt_2020_rgb_xyz_matrix[] = {
33     0.209559197891125,   0.047578961279863,   0.055561840829013,
34     0.086428369751707,   0.223061365529709,   0.019510264718585,
35     0.000000000000000,   0.009235916013150,   0.349064083986850
36 };
37 
38 const double bt_709_xyz_rgb_matrix[] = {
39     9.850972467794900,    -4.672897196261683,    -1.515534225814599,
40    -2.946029289607537,     5.702028879962675,     0.126307165371354,
41     0.169088388136759,    -0.619990756501448,     3.212679374598414
42 };
43 
44 const double bt_601_xyz_rgb_matrix[] = {
45     10.656544932293809,   -5.288117709127149,    -1.653672548215019,
46    -3.249384680406732,     6.011485965740993,     0.106904010143450,
47     0.171144655726832,    -0.598710197023623,     3.191344462670923
48 };
49 
50 const double bt_2020_xyz_rgb_matrix[] = {
51     5.217784765870115,    -1.081066212086299,    -0.770110277731489,
52    -2.026396206177778,     4.913316828677627,     0.047928710680581,
53     0.053616587979668,    -0.130001864005497,     2.863535322904176
54 };
55 
56 
57 static struct csc_table bgcolor_to_rgbfull_table[COLOR_SPACE_MAX] = {
58     [COLOR_SPACE_YCBCR601] =
59         {
60             {0.0f, -0.5f, -0.5f},
61             {1.0f, 0.0f, 1.402f},
62             {1.0f, -0.344136286f, -0.714136286f},
63             {1.0f, 1.772f, 0.0f},
64         },
65     [COLOR_SPACE_YCBCR709] =
66         {
67             {0.0f, -0.5f, -0.5f},
68             {1.0f, 0.0f, 1.5748f},
69             {1.0f, -0.187324273f, -0.468124273f},
70             {1.0f, 1.8556f, 0.0f},
71         },
72     [COLOR_SPACE_YCBCR601_LIMITED] =
73         {
74             {-0.0625f, -0.5f, -0.5f},
75             {1.164383562f, 0.0f, 1.596026786f},
76             {1.164383562f, -0.39176229f, -0.812967647f},
77             {1.164383562f, 2.017232143f, 0.0f},
78         },
79     [COLOR_SPACE_YCBCR709_LIMITED] =
80         {
81             {-0.0625f, -0.5f, -0.5f},
82             {1.164383562f, 0.0f, 1.792741071f},
83             {1.164383562f, -0.213248614f, -0.532909329f},
84             {1.164383562f, 2.112401786f, 0.0f},
85         },
86     [COLOR_SPACE_2020_YCBCR] =
87         {
88             {0.0f, -512.f / 1023.f, -512.f / 1023.f},
89             {1.0f, 0.0f, 1.4746f},
90             {1.0f, -0.164553127f, -0.571353127f},
91             {1.0f, 1.8814f, 0.0f},
92         },
93     [COLOR_SPACE_2020_YCBCR_LIMITED] =
94         {
95             {-0.0625f, -0.5f, -0.5f},
96             {1.167808219f, 0.0f, 1.683611384f},
97             {1.167808219f, -0.187877063f, -0.652337331f},
98             {1.167808219f, 2.148071652f, 0.0f},
99         },
100     [COLOR_SPACE_SRGB_LIMITED] =
101         {
102             {-0.0626221f, -0.0626221f, -0.0626221f},
103             {1.167783652f, 0.0f, 0.0f},
104             {0.0f, 1.167783652f, 0.0f},
105             {0.0f, 0.0, 1.167783652f},
106         },
107     [COLOR_SPACE_2020_RGB_LIMITEDRANGE] = {
108         {-0.0626221f, -0.0626221f, -0.0626221f},
109         {1.167783652f, 0.0f, 0.0f},
110         {0.0f, 1.167783652f, 0.0f},
111         {0.0f, 0.0, 1.167783652f},
112     }};
113 
clip_double(double x)114 static double clip_double(double x)
115 {
116     if (x < 0.0)
117         return 0.0;
118     else if (x > 1.0)
119         return 1.0;
120     else
121         return x;
122 }
123 
clip_float(float x)124 static float clip_float(float x)
125 {
126     if (x < 0.0f)
127         return 0.0f;
128     else if (x > 1.0f)
129         return 1.0f;
130     else
131         return x;
132 }
133 
color_multiply_matrices_double(double * mResult,double * M1,double * M2,unsigned int Rows1,unsigned int Cols1,unsigned int Cols2)134 static void color_multiply_matrices_double(double *mResult, double *M1,
135     double *M2, unsigned int Rows1, unsigned int Cols1, unsigned int Cols2)
136 {
137     unsigned int i, j, k;
138 
139     for (i = 0; i < Rows1; i++) {
140         for (j = 0; j < Cols2; j++) {
141             mResult[(i * Cols2) + j] = 0.0;
142             for (k = 0; k < Cols1; k++)
143                 mResult[(i * Cols2) + j] = mResult[(i * Cols2) + j] +
144                     M1[(i * Cols1) + k] * M2[(k * Cols2) + j];
145         }
146     }
147 }
148 
set_gamut_remap_matrix(double * res,enum color_space src_cs,enum color_space dst_cs)149 static void set_gamut_remap_matrix(double* res, enum color_space src_cs, enum color_space dst_cs) {
150 
151     double rgb_to_xyz[9] = { 0.0 };
152     double xyz_to_rgb[9] = { 0.0 };
153 
154     switch (src_cs)
155     {
156     case COLOR_SPACE_SRGB:
157     case COLOR_SPACE_SRGB_LIMITED:
158     case COLOR_SPACE_MSREF_SCRGB:
159     case COLOR_SPACE_YCBCR709_LIMITED:
160     case COLOR_SPACE_YCBCR709:
161     case COLOR_SPACE_YCBCR_JFIF:
162     case COLOR_SPACE_RGB_JFIF:
163         memcpy(rgb_to_xyz, bt_709_rgb_xyz_matrix, 9 * sizeof(double));
164         break;
165     case COLOR_SPACE_YCBCR601:
166     case COLOR_SPACE_YCBCR601_LIMITED:
167         memcpy(rgb_to_xyz, bt_601_rgb_xyz_matrix, 9 * sizeof(double));
168         break;
169     case COLOR_SPACE_2020_RGB_FULLRANGE:
170     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
171     case COLOR_SPACE_2020_YCBCR:
172     case COLOR_SPACE_2020_YCBCR_LIMITED:
173         memcpy(rgb_to_xyz, bt_2020_rgb_xyz_matrix, 9 * sizeof(double));
174         break;
175     default:
176         VPE_ASSERT(0);
177         break;
178     }
179 
180     switch (dst_cs)
181     {
182     case COLOR_SPACE_SRGB:
183     case COLOR_SPACE_SRGB_LIMITED:
184     case COLOR_SPACE_MSREF_SCRGB:
185     case COLOR_SPACE_YCBCR709_LIMITED:
186     case COLOR_SPACE_YCBCR709:
187     case COLOR_SPACE_YCBCR_JFIF:
188     case COLOR_SPACE_RGB_JFIF:
189         memcpy(xyz_to_rgb, bt_709_xyz_rgb_matrix, 9 * sizeof(double));
190         break;
191     case COLOR_SPACE_YCBCR601:
192     case COLOR_SPACE_YCBCR601_LIMITED:
193         memcpy(xyz_to_rgb, bt_601_xyz_rgb_matrix, 9 * sizeof(double));
194         break;
195     case COLOR_SPACE_2020_RGB_FULLRANGE:
196     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
197     case COLOR_SPACE_2020_YCBCR:
198     case COLOR_SPACE_2020_YCBCR_LIMITED:
199         memcpy(xyz_to_rgb, bt_2020_xyz_rgb_matrix, 9 * sizeof(double));
200         break;
201     default:
202         VPE_ASSERT(0);
203         break;
204     }
205 
206     color_multiply_matrices_double(res, xyz_to_rgb, rgb_to_xyz, 3, 3, 3);
207 
208 }
209 
bg_csc(struct vpe_color * bg_color,enum color_space cs)210 static bool bg_csc(struct vpe_color *bg_color, enum color_space cs)
211 {
212     struct csc_table *entry             = &bgcolor_to_rgbfull_table[cs];
213     float             csc_final[3]      = {0};
214     float             csc_mm[3][4]      = {0};
215     bool              output_is_clipped = false;
216 
217     memcpy(&csc_mm[0][0], &entry->red_coef, sizeof(struct csc_vector));
218     memcpy(&csc_mm[1][0], &entry->green_coef, sizeof(struct csc_vector));
219     memcpy(&csc_mm[2][0], &entry->blue_coef, sizeof(struct csc_vector));
220 
221     csc_mm[0][3] = entry->rgb_offset.x * csc_mm[0][0] + entry->rgb_offset.y * csc_mm[0][1] +
222                    entry->rgb_offset.z * csc_mm[0][2];
223 
224     csc_mm[1][3] = entry->rgb_offset.x * csc_mm[1][0] + entry->rgb_offset.y * csc_mm[1][1] +
225                    entry->rgb_offset.z * csc_mm[1][2];
226 
227     csc_mm[2][3] = entry->rgb_offset.x * csc_mm[2][0] + entry->rgb_offset.y * csc_mm[2][1] +
228                    entry->rgb_offset.z * csc_mm[2][2];
229 
230     csc_final[0] = csc_mm[0][0] * bg_color->ycbcra.y + csc_mm[0][1] * bg_color->ycbcra.cb +
231                    csc_mm[0][2] * bg_color->ycbcra.cr + csc_mm[0][3];
232 
233     csc_final[1] = csc_mm[1][0] * bg_color->ycbcra.y + csc_mm[1][1] * bg_color->ycbcra.cb +
234                    csc_mm[1][2] * bg_color->ycbcra.cr + csc_mm[1][3];
235 
236     csc_final[2] = csc_mm[2][0] * bg_color->ycbcra.y + csc_mm[2][1] * bg_color->ycbcra.cb +
237                    csc_mm[2][2] * bg_color->ycbcra.cr + csc_mm[2][3];
238 
239     // switch to RGB components
240     bg_color->rgba.a = bg_color->ycbcra.a;
241     bg_color->rgba.r = clip_float(csc_final[0]);
242     bg_color->rgba.g = clip_float(csc_final[1]);
243     bg_color->rgba.b = clip_float(csc_final[2]);
244     if ((bg_color->rgba.r != csc_final[0]) || (bg_color->rgba.g != csc_final[1]) ||
245         (bg_color->rgba.b != csc_final[2])) {
246         output_is_clipped = true;
247     }
248     bg_color->is_ycbcr = false;
249     return output_is_clipped;
250 }
251 
is_global_bg_blend_applied(struct stream_ctx * stream_ctx)252 static inline bool is_global_bg_blend_applied(struct stream_ctx *stream_ctx) {
253 
254     return (stream_ctx->stream.blend_info.blending)  &&
255         (stream_ctx->stream.blend_info.global_alpha) &&
256         (stream_ctx->stream.blend_info.global_alpha_value != 1.0);
257 }
258 
259 /*
260     In order to support background color fill correctly, we need to do studio -> full range conversion
261     before the blend block. However, there is also a requirement for HDR output to be blended in linear space.
262     Hence, if we have PQ out and studio range, we need to make sure no blenidng will occur. Othewise the job
263     is invalid.
264 
265 */
is_valid_blend(const struct vpe_priv * vpe_priv,struct vpe_color * bg_color)266 static enum vpe_status is_valid_blend(const struct vpe_priv *vpe_priv, struct vpe_color *bg_color) {
267 
268     enum vpe_status status = VPE_STATUS_OK;
269     const struct vpe_color_space *vcs = &vpe_priv->output_ctx.surface.cs;
270     struct stream_ctx *stream_ctx = vpe_priv->stream_ctx;  //Only need to check the first stream.
271 
272     if ((vcs->range == VPE_COLOR_RANGE_STUDIO) &&
273         (vcs->tf == VPE_TF_PQ) &&
274         ((stream_ctx->stream.surface_info.cs.encoding == VPE_PIXEL_ENCODING_RGB) ||
275             is_global_bg_blend_applied(stream_ctx)))
276         status = VPE_STATUS_BG_COLOR_OUT_OF_RANGE;
277 
278     return status;
279 }
280 
281 struct gamma_coefs {
282     float a0;
283     float a1;
284     float a2;
285     float a3;
286     float user_gamma;
287     float user_contrast;
288     float user_brightness;
289 };
290 
291 // srgb, 709, G24
292 static const int32_t numerator01[] = {31308, 180000, 0};
293 static const int32_t numerator02[] = {12920, 4500, 0};
294 static const int32_t numerator03[] = {55, 99, 0};
295 static const int32_t numerator04[] = {55, 99, 0};
296 static const int32_t numerator05[] = {2400, 2222, 2400};
297 
build_coefficients(struct gamma_coefs * coefficients,enum color_transfer_func type)298 static bool build_coefficients(struct gamma_coefs *coefficients, enum color_transfer_func type)
299 {
300     uint32_t index = 0;
301     bool     ret   = true;
302 
303     if (type == TRANSFER_FUNC_SRGB)
304         index = 0;
305     else if (type == TRANSFER_FUNC_BT709)
306         index = 1;
307     else if (type == TRANSFER_FUNC_BT1886)
308         index = 2;
309     else {
310         ret = false;
311         goto release;
312     }
313 
314     coefficients->a0         = (float)numerator01[index] / 10000000.0f;
315     coefficients->a1         = (float)numerator02[index] / 1000.0f;
316     coefficients->a2         = (float)numerator03[index] / 1000.0f;
317     coefficients->a3         = (float)numerator04[index] / 1000.0f;
318     coefficients->user_gamma = (float)numerator05[index] / 1000.0f;
319 
320 release:
321     return ret;
322 }
323 
translate_to_linear_space(double arg,double a0,double a1,double a2,double a3,double gamma)324 static double translate_to_linear_space(
325     double arg, double a0, double a1, double a2, double a3, double gamma)
326 {
327     double linear;
328     double base;
329 
330     a0 *= a1;
331     if (arg <= -a0) {
332         base   = (a2 - arg) / (1.0 + a3);
333         linear = -pow(base, gamma);
334     } else if ((-a0 <= arg) && (arg <= a0))
335         linear = arg / a1;
336     else {
337         base   = (a2 + arg) / (1.0 + a3);
338         linear = pow(base, gamma);
339     }
340 
341     return linear;
342 }
343 
344 // for 709 & sRGB
compute_degam(enum color_transfer_func tf,double inY,double * outX,bool clip)345 static void compute_degam(enum color_transfer_func tf, double inY, double *outX, bool clip)
346 {
347     double             ret;
348     struct gamma_coefs coefs = {0};
349 
350     build_coefficients(&coefs, tf);
351 
352     ret = translate_to_linear_space(inY, (double)coefs.a0, (double)coefs.a1, (double)coefs.a2,
353         (double)coefs.a3, (double)coefs.user_gamma);
354 
355     if (clip) {
356         ret = clip_double(ret);
357     }
358     *outX = ret;
359 }
360 
get_maximum_fp(double a,double b)361 static double get_maximum_fp(double a, double b)
362 {
363     if (a > b)
364         return a;
365     return b;
366 }
367 
compute_depq(double inY,double * outX,bool clip)368 static void compute_depq(double inY, double *outX, bool clip)
369 {
370     double M1 = 0.159301758;
371     double M2 = 78.84375;
372     double C1 = 0.8359375;
373     double C2 = 18.8515625;
374     double C3 = 18.6875;
375 
376     double nPowM2;
377     double base;
378     double one      = 1.0;
379     double zero     = 0.0;
380     bool   negative = false;
381     double ret;
382 
383     if (inY < zero) {
384         inY      = -inY;
385         negative = true;
386     }
387     nPowM2 = pow(inY, one / M2);
388     base   = get_maximum_fp(nPowM2 - C1, zero) / (C2 - C3 * nPowM2);
389     ret    = pow(base, one / M1);
390     if (clip) {
391         ret = clip_double(ret);
392     }
393     if (negative)
394         ret = -ret;
395 
396     *outX = ret;
397 }
398 
is_limited_cs(enum color_space cs)399 static bool is_limited_cs(enum color_space cs)
400 {
401     bool is_limited = false;
402 
403     switch (cs)
404     {
405     case COLOR_SPACE_SRGB:
406     case COLOR_SPACE_2020_RGB_FULLRANGE:
407     case COLOR_SPACE_MSREF_SCRGB:
408     case COLOR_SPACE_YCBCR601:
409     case COLOR_SPACE_YCBCR709:
410     case COLOR_SPACE_YCBCR_JFIF:
411     case COLOR_SPACE_RGB_JFIF:
412     case COLOR_SPACE_2020_YCBCR:
413         is_limited = false;
414         break;
415     case COLOR_SPACE_SRGB_LIMITED:
416     case COLOR_SPACE_YCBCR601_LIMITED:
417     case COLOR_SPACE_YCBCR709_LIMITED:
418     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
419     case COLOR_SPACE_2020_YCBCR_LIMITED:
420         is_limited = true;
421         break;
422     default:
423         VPE_ASSERT(0);
424         is_limited = false;
425         break;
426     }
427     return is_limited;
428 }
429 
vpe_bg_degam(struct transfer_func * output_tf,struct vpe_color * bg_color)430 static void vpe_bg_degam(
431     struct transfer_func *output_tf, struct vpe_color *bg_color) {
432 
433     double degam_r = (double)bg_color->rgba.r;
434     double degam_g = (double)bg_color->rgba.g;
435     double degam_b = (double)bg_color->rgba.b;
436 
437     // de-gam
438     switch (output_tf->tf) {
439 
440     case TRANSFER_FUNC_PQ2084:
441         compute_depq((double)bg_color->rgba.r, &degam_r, true);
442         compute_depq((double)bg_color->rgba.g, &degam_g, true);
443         compute_depq((double)bg_color->rgba.b, &degam_b, true);
444         break;
445     case TRANSFER_FUNC_SRGB:
446     case TRANSFER_FUNC_BT709:
447     case TRANSFER_FUNC_BT1886:
448         compute_degam(output_tf->tf, (double)bg_color->rgba.r, &degam_r, true);
449         compute_degam(output_tf->tf, (double)bg_color->rgba.g, &degam_g, true);
450         compute_degam(output_tf->tf, (double)bg_color->rgba.b, &degam_b, true);
451         break;
452     case TRANSFER_FUNC_LINEAR:
453         break;
454     default:
455         VPE_ASSERT(0);
456         break;
457     }
458     bg_color->rgba.r = (float)degam_r;
459     bg_color->rgba.g = (float)degam_g;
460     bg_color->rgba.b = (float)degam_b;
461 
462 }
463 
vpe_bg_inverse_gamut_remap(enum color_space output_cs,struct transfer_func * output_tf,struct vpe_color * bg_color)464 static void vpe_bg_inverse_gamut_remap(enum color_space output_cs,
465     struct transfer_func *output_tf, struct vpe_color *bg_color)
466 {
467 
468         double bg_rgb[3] = { 0.0 };
469         double final_bg_rgb[3] = { 0.0 };
470         double matrix[9] = { 0.0 };
471         bg_rgb[0] = (double)bg_color->rgba.r;
472         bg_rgb[1] = (double)bg_color->rgba.g;
473         bg_rgb[2] = (double)bg_color->rgba.b;
474 
475         switch (output_tf->tf) {
476         case TRANSFER_FUNC_LINEAR:
477             /* Since linear output uses Bt709, and this conversion is only needed
478              * when the tone mapping is enabled on (Bt2020) input, it is needed to
479              * apply the reverse of Bt2020 -> Bt709 on the background color to
480              * cancel out the effect of Bt2020 -> Bt709 on the background color.
481              */
482             set_gamut_remap_matrix(matrix, COLOR_SPACE_SRGB, COLOR_SPACE_2020_RGB_FULLRANGE);
483             color_multiply_matrices_double(final_bg_rgb, matrix, bg_rgb, 3, 3, 1);
484 
485             bg_color->rgba.r = (float)clip_double(final_bg_rgb[0]);
486             bg_color->rgba.g = (float)clip_double(final_bg_rgb[1]);
487             bg_color->rgba.b = (float)clip_double(final_bg_rgb[2]);
488 
489             break;
490         case TRANSFER_FUNC_PQ2084:
491         case TRANSFER_FUNC_SRGB:
492         case TRANSFER_FUNC_BT709:
493         case TRANSFER_FUNC_BT1886:
494             break;
495         default:
496             VPE_ASSERT(0);
497             break;
498         }
499 
500 }
501 
inverse_output_csc(enum color_space output_cs,struct vpe_color * bg_color)502 static void inverse_output_csc(enum color_space output_cs, struct vpe_color* bg_color)
503 {
504     enum color_space bgcolor_cs = COLOR_SPACE_YCBCR709;
505 
506     switch (output_cs) {
507         // output is ycbr cs, follow output's setting
508     case COLOR_SPACE_YCBCR601:
509     case COLOR_SPACE_YCBCR709:
510     case COLOR_SPACE_YCBCR601_LIMITED:
511     case COLOR_SPACE_YCBCR709_LIMITED:
512     case COLOR_SPACE_2020_YCBCR:
513     case COLOR_SPACE_2020_YCBCR_LIMITED:
514         bgcolor_cs = output_cs;
515         break;
516         // output is RGB cs, follow output's range
517         // but need yuv to rgb csc
518     case COLOR_SPACE_SRGB_LIMITED:
519     case COLOR_SPACE_RGB601_LIMITED:
520         bgcolor_cs = COLOR_SPACE_YCBCR709_LIMITED;
521         break;
522     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
523         bgcolor_cs = COLOR_SPACE_2020_YCBCR_LIMITED;
524         break;
525     case COLOR_SPACE_SRGB:
526     case COLOR_SPACE_MSREF_SCRGB:
527     case COLOR_SPACE_RGB601:
528         bgcolor_cs = COLOR_SPACE_YCBCR709;
529         break;
530     case COLOR_SPACE_2020_RGB_FULLRANGE:
531         bgcolor_cs = COLOR_SPACE_2020_YCBCR;
532         break;
533     default:
534         // should revise the newly added CS
535         // and set corresponding bgcolor_cs accordingly
536         VPE_ASSERT(0);
537         bgcolor_cs = COLOR_SPACE_YCBCR709;
538         break;
539     }
540 
541     // input is [0-0xffff]
542     // convert bg color to RGB full range for use inside pipe
543     bg_csc(bg_color, bgcolor_cs);
544 }
545 
546 // To understand the logic for background color conversion,
547 // 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,struct vpe_color * bg_color,bool enable_3dlut)548 void vpe_bg_color_convert(
549     enum color_space output_cs, struct transfer_func *output_tf, struct vpe_color *bg_color, bool enable_3dlut)
550 {
551     // inverse OCSC
552     if (bg_color->is_ycbcr)
553         inverse_output_csc(output_cs, bg_color);
554 
555     if (output_tf->type != TF_TYPE_BYPASS) {
556         // inverse degam
557         if (output_tf->tf == TRANSFER_FUNC_PQ2084 && !is_limited_cs(output_cs))
558             vpe_bg_degam(output_tf, bg_color);
559         // inverse gamut remap
560         if (enable_3dlut)
561             vpe_bg_inverse_gamut_remap(output_cs, output_tf, bg_color);
562     }
563     // for TF_TYPE_BYPASS, bg color should be programmed to mpc as linear
564 }
565 
vpe_bg_color_outside_cs_gamut(const struct vpe_priv * vpe_priv,struct vpe_color * bg_color)566 enum vpe_status vpe_bg_color_outside_cs_gamut(
567     const struct vpe_priv *vpe_priv, struct vpe_color *bg_color)
568 {
569     enum color_space         cs;
570     enum color_transfer_func tf;
571     struct vpe_color         bg_color_copy = *bg_color;
572     const struct vpe_color_space *vcs      = &vpe_priv->output_ctx.surface.cs;
573 
574     vpe_color_get_color_space_and_tf(vcs, &cs, &tf);
575 
576     if ((bg_color->is_ycbcr)) {
577         // using the bg_color_copy instead as bg_csc will modify it
578         // we should not do modification in checking stage
579         // otherwise validate_cached_param() will fail
580         if (bg_csc(&bg_color_copy, cs)) {
581             return VPE_STATUS_BG_COLOR_OUT_OF_RANGE;
582         }
583     }
584     return VPE_STATUS_OK;
585 }
586 
is_target_rect_equal_to_dest_rect(const struct vpe_priv * vpe_priv)587 static inline bool is_target_rect_equal_to_dest_rect(const struct vpe_priv *vpe_priv)
588 {
589     const struct vpe_rect *target_rect = &vpe_priv->output_ctx.target_rect;
590     const struct vpe_rect *dst_rect = &vpe_priv->stream_ctx[0].stream.scaling_info.dst_rect;
591 
592     return (target_rect->height == dst_rect ->height) && (target_rect->width  == dst_rect ->width) &&
593            (target_rect->x == dst_rect ->x) && (target_rect->y == dst_rect ->y);
594 }
595 
596 // These two checks are only necessary for VPE1.0 and contain a lot of quirks to work around VPE 1.0
597 // limitations.
vpe_is_valid_bg_color(const struct vpe_priv * vpe_priv,struct vpe_color * bg_color)598 enum vpe_status vpe_is_valid_bg_color(const struct vpe_priv *vpe_priv, struct vpe_color *bg_color) {
599 
600     enum vpe_status status = VPE_STATUS_OK;
601 
602     /* no need for background filling as for target rect equal to dest rect */
603     if (is_target_rect_equal_to_dest_rect(vpe_priv)) {
604         return VPE_STATUS_OK;
605     }
606 
607     status = is_valid_blend(vpe_priv, bg_color);
608 
609     if (status == VPE_STATUS_OK)
610         status = vpe_bg_color_outside_cs_gamut(vpe_priv, bg_color);
611 
612     return status;
613 }
614