• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_JFIF:
162         memcpy(rgb_to_xyz, bt_709_rgb_xyz_matrix, 9 * sizeof(double));
163         break;
164     case COLOR_SPACE_YCBCR601:
165     case COLOR_SPACE_YCBCR601_LIMITED:
166         memcpy(rgb_to_xyz, bt_601_rgb_xyz_matrix, 9 * sizeof(double));
167         break;
168     case COLOR_SPACE_2020_RGB_FULLRANGE:
169     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
170     case COLOR_SPACE_2020_YCBCR:
171     case COLOR_SPACE_2020_YCBCR_LIMITED:
172         memcpy(rgb_to_xyz, bt_2020_rgb_xyz_matrix, 9 * sizeof(double));
173         break;
174     default:
175         VPE_ASSERT(0);
176         break;
177     }
178 
179     switch (dst_cs)
180     {
181     case COLOR_SPACE_SRGB:
182     case COLOR_SPACE_SRGB_LIMITED:
183     case COLOR_SPACE_MSREF_SCRGB:
184     case COLOR_SPACE_YCBCR709_LIMITED:
185     case COLOR_SPACE_YCBCR709:
186     case COLOR_SPACE_JFIF:
187         memcpy(xyz_to_rgb, bt_709_xyz_rgb_matrix, 9 * sizeof(double));
188         break;
189     case COLOR_SPACE_YCBCR601:
190     case COLOR_SPACE_YCBCR601_LIMITED:
191         memcpy(xyz_to_rgb, bt_601_xyz_rgb_matrix, 9 * sizeof(double));
192         break;
193     case COLOR_SPACE_2020_RGB_FULLRANGE:
194     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
195     case COLOR_SPACE_2020_YCBCR:
196     case COLOR_SPACE_2020_YCBCR_LIMITED:
197         memcpy(xyz_to_rgb, bt_2020_xyz_rgb_matrix, 9 * sizeof(double));
198         break;
199     default:
200         VPE_ASSERT(0);
201         break;
202     }
203 
204     color_multiply_matrices_double(res, xyz_to_rgb, rgb_to_xyz, 3, 3, 3);
205 
206 }
207 
bg_csc(struct vpe_color * bg_color,enum color_space cs)208 static bool bg_csc(struct vpe_color *bg_color, enum color_space cs)
209 {
210     struct csc_table *entry             = &bgcolor_to_rgbfull_table[cs];
211     float             csc_final[3]      = {0};
212     float             csc_mm[3][4]      = {0};
213     bool              output_is_clipped = false;
214 
215     memcpy(&csc_mm[0][0], &entry->red_coef, sizeof(struct csc_vector));
216     memcpy(&csc_mm[1][0], &entry->green_coef, sizeof(struct csc_vector));
217     memcpy(&csc_mm[2][0], &entry->blue_coef, sizeof(struct csc_vector));
218 
219     csc_mm[0][3] = entry->rgb_offset.x * csc_mm[0][0] + entry->rgb_offset.y * csc_mm[0][1] +
220                    entry->rgb_offset.z * csc_mm[0][2];
221 
222     csc_mm[1][3] = entry->rgb_offset.x * csc_mm[1][0] + entry->rgb_offset.y * csc_mm[1][1] +
223                    entry->rgb_offset.z * csc_mm[1][2];
224 
225     csc_mm[2][3] = entry->rgb_offset.x * csc_mm[2][0] + entry->rgb_offset.y * csc_mm[2][1] +
226                    entry->rgb_offset.z * csc_mm[2][2];
227 
228     csc_final[0] = csc_mm[0][0] * bg_color->ycbcra.y + csc_mm[0][1] * bg_color->ycbcra.cb +
229                    csc_mm[0][2] * bg_color->ycbcra.cr + csc_mm[0][3];
230 
231     csc_final[1] = csc_mm[1][0] * bg_color->ycbcra.y + csc_mm[1][1] * bg_color->ycbcra.cb +
232                    csc_mm[1][2] * bg_color->ycbcra.cr + csc_mm[1][3];
233 
234     csc_final[2] = csc_mm[2][0] * bg_color->ycbcra.y + csc_mm[2][1] * bg_color->ycbcra.cb +
235                    csc_mm[2][2] * bg_color->ycbcra.cr + csc_mm[2][3];
236 
237     // switch to RGB components
238     bg_color->rgba.a = bg_color->ycbcra.a;
239     bg_color->rgba.r = clip_float(csc_final[0]);
240     bg_color->rgba.g = clip_float(csc_final[1]);
241     bg_color->rgba.b = clip_float(csc_final[2]);
242     if ((bg_color->rgba.r != csc_final[0]) || (bg_color->rgba.g != csc_final[1]) ||
243         (bg_color->rgba.b != csc_final[2])) {
244         output_is_clipped = true;
245     }
246     bg_color->is_ycbcr = false;
247     return output_is_clipped;
248 }
249 
is_global_bg_blend_applied(struct stream_ctx * stream_ctx)250 static inline bool is_global_bg_blend_applied(struct stream_ctx *stream_ctx) {
251 
252     return (stream_ctx->stream.blend_info.blending)  &&
253         (stream_ctx->stream.blend_info.global_alpha) &&
254         (stream_ctx->stream.blend_info.global_alpha_value != 1.0);
255 }
256 
257 /*
258     In order to support background color fill correctly, we need to do studio -> full range conversion
259     before the blend block. However, there is also a requirement for HDR output to be blended in linear space.
260     Hence, if we have PQ out and studio range, we need to make sure no blenidng will occur. Othewise the job
261     is invalid.
262 
263 */
is_valid_blend(const struct vpe_priv * vpe_priv,struct vpe_color * bg_color)264 static enum vpe_status is_valid_blend(const struct vpe_priv *vpe_priv, struct vpe_color *bg_color) {
265 
266     enum vpe_status status = VPE_STATUS_OK;
267     const struct vpe_color_space *vcs = &vpe_priv->output_ctx.surface.cs;
268     struct stream_ctx *stream_ctx = vpe_priv->stream_ctx;  //Only need to check the first stream.
269 
270     if ((vcs->range == VPE_COLOR_RANGE_STUDIO) &&
271         (vcs->tf == VPE_TF_PQ) &&
272         ((stream_ctx->stream.surface_info.cs.encoding == VPE_PIXEL_ENCODING_RGB) ||
273             is_global_bg_blend_applied(stream_ctx)))
274         status = VPE_STATUS_BG_COLOR_OUT_OF_RANGE;
275 
276     return status;
277 }
278 
279 struct gamma_coefs {
280     float a0;
281     float a1;
282     float a2;
283     float a3;
284     float user_gamma;
285     float user_contrast;
286     float user_brightness;
287 };
288 
289 // srgb, 709, G24
290 static const int32_t numerator01[] = {31308, 180000, 0};
291 static const int32_t numerator02[] = {12920, 4500, 0};
292 static const int32_t numerator03[] = {55, 99, 0};
293 static const int32_t numerator04[] = {55, 99, 0};
294 static const int32_t numerator05[] = {2400, 2222, 2400};
295 
build_coefficients(struct gamma_coefs * coefficients,enum color_transfer_func type)296 static bool build_coefficients(struct gamma_coefs *coefficients, enum color_transfer_func type)
297 {
298     uint32_t index = 0;
299     bool     ret   = true;
300 
301     if (type == TRANSFER_FUNC_SRGB)
302         index = 0;
303     else if (type == TRANSFER_FUNC_BT709)
304         index = 1;
305     else if (type == TRANSFER_FUNC_BT1886)
306         index = 2;
307     else {
308         ret = false;
309         goto release;
310     }
311 
312     coefficients->a0         = (float)numerator01[index] / 10000000.0f;
313     coefficients->a1         = (float)numerator02[index] / 1000.0f;
314     coefficients->a2         = (float)numerator03[index] / 1000.0f;
315     coefficients->a3         = (float)numerator04[index] / 1000.0f;
316     coefficients->user_gamma = (float)numerator05[index] / 1000.0f;
317 
318 release:
319     return ret;
320 }
321 
translate_to_linear_space(double arg,double a0,double a1,double a2,double a3,double gamma)322 static double translate_to_linear_space(
323     double arg, double a0, double a1, double a2, double a3, double gamma)
324 {
325     double linear;
326     double base;
327 
328     a0 *= a1;
329     if (arg <= -a0) {
330         base   = (a2 - arg) / (1.0 + a3);
331         linear = -pow(base, gamma);
332     } else if ((-a0 <= arg) && (arg <= a0))
333         linear = arg / a1;
334     else {
335         base   = (a2 + arg) / (1.0 + a3);
336         linear = pow(base, gamma);
337     }
338 
339     return linear;
340 }
341 
342 // for 709 & sRGB
compute_degam(enum color_transfer_func tf,double inY,double * outX,bool clip)343 static void compute_degam(enum color_transfer_func tf, double inY, double *outX, bool clip)
344 {
345     double             ret;
346     struct gamma_coefs coefs = {0};
347 
348     build_coefficients(&coefs, tf);
349 
350     ret = translate_to_linear_space(inY, (double)coefs.a0, (double)coefs.a1, (double)coefs.a2,
351         (double)coefs.a3, (double)coefs.user_gamma);
352 
353     if (clip) {
354         ret = clip_double(ret);
355     }
356     *outX = ret;
357 }
358 
get_maximum_fp(double a,double b)359 static double get_maximum_fp(double a, double b)
360 {
361     if (a > b)
362         return a;
363     return b;
364 }
365 
compute_depq(double inY,double * outX,bool clip)366 static void compute_depq(double inY, double *outX, bool clip)
367 {
368     double M1 = 0.159301758;
369     double M2 = 78.84375;
370     double C1 = 0.8359375;
371     double C2 = 18.8515625;
372     double C3 = 18.6875;
373 
374     double nPowM2;
375     double base;
376     double one      = 1.0;
377     double zero     = 0.0;
378     bool   negative = false;
379     double ret;
380 
381     if (inY < zero) {
382         inY      = -inY;
383         negative = true;
384     }
385     nPowM2 = pow(inY, one / M2);
386     base   = get_maximum_fp(nPowM2 - C1, zero) / (C2 - C3 * nPowM2);
387     ret    = pow(base, one / M1);
388     if (clip) {
389         ret = clip_double(ret);
390     }
391     if (negative)
392         ret = -ret;
393 
394     *outX = ret;
395 }
396 
is_limited_cs(enum color_space cs)397 static bool is_limited_cs(enum color_space cs)
398 {
399     bool is_limited = false;
400 
401     switch (cs)
402     {
403     case COLOR_SPACE_SRGB:
404     case COLOR_SPACE_2020_RGB_FULLRANGE:
405     case COLOR_SPACE_MSREF_SCRGB:
406     case COLOR_SPACE_YCBCR601:
407     case COLOR_SPACE_YCBCR709:
408     case COLOR_SPACE_JFIF:
409     case COLOR_SPACE_2020_YCBCR:
410         is_limited = false;
411         break;
412     case COLOR_SPACE_SRGB_LIMITED:
413     case COLOR_SPACE_YCBCR601_LIMITED:
414     case COLOR_SPACE_YCBCR709_LIMITED:
415     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
416     case COLOR_SPACE_2020_YCBCR_LIMITED:
417         is_limited = true;
418         break;
419     default:
420         VPE_ASSERT(0);
421         is_limited = false;
422         break;
423     }
424     return is_limited;
425 }
426 
vpe_bg_degam(struct transfer_func * output_tf,struct vpe_color * bg_color)427 static void vpe_bg_degam(
428     struct transfer_func *output_tf, struct vpe_color *bg_color) {
429 
430     double degam_r = (double)bg_color->rgba.r;
431     double degam_g = (double)bg_color->rgba.g;
432     double degam_b = (double)bg_color->rgba.b;
433 
434     // de-gam
435     switch (output_tf->tf) {
436 
437     case TRANSFER_FUNC_PQ2084:
438         compute_depq((double)bg_color->rgba.r, &degam_r, true);
439         compute_depq((double)bg_color->rgba.g, &degam_g, true);
440         compute_depq((double)bg_color->rgba.b, &degam_b, true);
441         break;
442     case TRANSFER_FUNC_SRGB:
443     case TRANSFER_FUNC_BT709:
444     case TRANSFER_FUNC_BT1886:
445         compute_degam(output_tf->tf, (double)bg_color->rgba.r, &degam_r, true);
446         compute_degam(output_tf->tf, (double)bg_color->rgba.g, &degam_g, true);
447         compute_degam(output_tf->tf, (double)bg_color->rgba.b, &degam_b, true);
448         break;
449     case TRANSFER_FUNC_LINEAR_0_125:
450     case TRANSFER_FUNC_LINEAR_0_1:
451         break;
452     default:
453         VPE_ASSERT(0);
454         break;
455     }
456     bg_color->rgba.r = (float)degam_r;
457     bg_color->rgba.g = (float)degam_g;
458     bg_color->rgba.b = (float)degam_b;
459 
460 }
461 
vpe_bg_inverse_gamut_remap(enum color_space output_cs,struct transfer_func * output_tf,struct vpe_color * bg_color)462 static void vpe_bg_inverse_gamut_remap(enum color_space output_cs,
463     struct transfer_func *output_tf, struct vpe_color *bg_color)
464 {
465 
466         double bg_rgb[3] = { 0.0 };
467         double final_bg_rgb[3] = { 0.0 };
468         double matrix[9] = { 0.0 };
469         bg_rgb[0] = (double)bg_color->rgba.r;
470         bg_rgb[1] = (double)bg_color->rgba.g;
471         bg_rgb[2] = (double)bg_color->rgba.b;
472 
473         switch (output_tf->tf) {
474         case TRANSFER_FUNC_LINEAR_0_1:
475         case TRANSFER_FUNC_LINEAR_0_125:
476             /* Since linear output uses Bt709, and this conversion is only needed
477              * when the tone mapping is enabled on (Bt2020) input, it is needed to
478              * apply the reverse of Bt2020 -> Bt709 on the background color to
479              * cancel out the effect of Bt2020 -> Bt709 on the background color.
480              */
481             set_gamut_remap_matrix(matrix, COLOR_SPACE_SRGB, COLOR_SPACE_2020_RGB_FULLRANGE);
482             color_multiply_matrices_double(final_bg_rgb, matrix, bg_rgb, 3, 3, 1);
483 
484             bg_color->rgba.r = (float)clip_double(final_bg_rgb[0]);
485             bg_color->rgba.g = (float)clip_double(final_bg_rgb[1]);
486             bg_color->rgba.b = (float)clip_double(final_bg_rgb[2]);
487 
488             break;
489         case TRANSFER_FUNC_PQ2084:
490         case TRANSFER_FUNC_SRGB:
491         case TRANSFER_FUNC_BT709:
492         case TRANSFER_FUNC_BT1886:
493             break;
494         default:
495             VPE_ASSERT(0);
496             break;
497         }
498 
499 }
500 
inverse_output_csc(enum color_space output_cs,struct vpe_color * bg_color)501 static void inverse_output_csc(enum color_space output_cs, struct vpe_color* bg_color)
502 {
503     enum color_space bgcolor_cs = COLOR_SPACE_YCBCR709;
504 
505     switch (output_cs) {
506         // output is ycbr cs, follow output's setting
507     case COLOR_SPACE_YCBCR601:
508     case COLOR_SPACE_YCBCR709:
509     case COLOR_SPACE_YCBCR601_LIMITED:
510     case COLOR_SPACE_YCBCR709_LIMITED:
511     case COLOR_SPACE_2020_YCBCR:
512     case COLOR_SPACE_2020_YCBCR_LIMITED:
513         bgcolor_cs = output_cs;
514         break;
515         // output is RGB cs, follow output's range
516         // but need yuv to rgb csc
517     case COLOR_SPACE_SRGB_LIMITED:
518         bgcolor_cs = COLOR_SPACE_YCBCR709_LIMITED;
519         break;
520     case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
521         bgcolor_cs = COLOR_SPACE_2020_YCBCR_LIMITED;
522         break;
523     case COLOR_SPACE_SRGB:
524     case COLOR_SPACE_MSREF_SCRGB:
525         bgcolor_cs = COLOR_SPACE_YCBCR709;
526         break;
527     case COLOR_SPACE_2020_RGB_FULLRANGE:
528         bgcolor_cs = COLOR_SPACE_2020_YCBCR;
529         break;
530     default:
531         // should revise the newly added CS
532         // and set corresponding bgcolor_cs accordingly
533         VPE_ASSERT(0);
534         bgcolor_cs = COLOR_SPACE_YCBCR709;
535         break;
536     }
537 
538     // input is [0-0xffff]
539     // convert bg color to RGB full range for use inside pipe
540     bg_csc(bg_color, bgcolor_cs);
541 }
542 
543 // To understand the logic for background color conversion,
544 // 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)545 void vpe_bg_color_convert(
546     enum color_space output_cs, struct transfer_func *output_tf, struct vpe_color *bg_color, bool enable_3dlut)
547 {
548     // inverse OCSC
549     if (bg_color->is_ycbcr)
550         inverse_output_csc(output_cs, bg_color);
551 
552     if (output_tf->type != TF_TYPE_BYPASS) {
553         // inverse degam
554         if (output_tf->tf == TRANSFER_FUNC_PQ2084 && !is_limited_cs(output_cs))
555             vpe_bg_degam(output_tf, bg_color);
556         // inverse gamut remap
557         if (enable_3dlut)
558             vpe_bg_inverse_gamut_remap(output_cs, output_tf, bg_color);
559     }
560     // for TF_TYPE_BYPASS, bg color should be programmed to mpc as linear
561 }
562 
vpe_bg_color_outside_cs_gamut(const struct vpe_priv * vpe_priv,struct vpe_color * bg_color)563 enum vpe_status vpe_bg_color_outside_cs_gamut(
564     const struct vpe_priv *vpe_priv, struct vpe_color *bg_color)
565 {
566     enum color_space         cs;
567     enum color_transfer_func tf;
568     struct vpe_color         bg_color_copy = *bg_color;
569     const struct vpe_color_space *vcs      = &vpe_priv->output_ctx.surface.cs;
570 
571     vpe_color_get_color_space_and_tf(vcs, &cs, &tf);
572 
573     if ((bg_color->is_ycbcr)) {
574         // using the bg_color_copy instead as bg_csc will modify it
575         // we should not do modification in checking stage
576         // otherwise validate_cached_param() will fail
577         if (bg_csc(&bg_color_copy, cs)) {
578             return VPE_STATUS_BG_COLOR_OUT_OF_RANGE;
579         }
580     }
581     return VPE_STATUS_OK;
582 }
583 
is_target_rect_equal_to_dest_rect(const struct vpe_priv * vpe_priv)584 static inline bool is_target_rect_equal_to_dest_rect(const struct vpe_priv *vpe_priv)
585 {
586     const struct vpe_rect *target_rect = &vpe_priv->output_ctx.target_rect;
587     const struct vpe_rect *dst_rect = &vpe_priv->stream_ctx[0].stream.scaling_info.dst_rect;
588 
589     return (target_rect->height == dst_rect ->height) && (target_rect->width  == dst_rect ->width) &&
590            (target_rect->x == dst_rect ->x) && (target_rect->y == dst_rect ->y);
591 }
592 
593 // These two checks are only necessary for VPE1.0 and contain a lot of quirks to work around VPE 1.0
594 // limitations.
vpe_is_valid_bg_color(const struct vpe_priv * vpe_priv,struct vpe_color * bg_color)595 enum vpe_status vpe_is_valid_bg_color(const struct vpe_priv *vpe_priv, struct vpe_color *bg_color) {
596 
597     enum vpe_status status = VPE_STATUS_OK;
598 
599     /* no need for background filling as for target rect equal to dest rect */
600     if (is_target_rect_equal_to_dest_rect(vpe_priv)) {
601         return VPE_STATUS_OK;
602     }
603 
604     status = is_valid_blend(vpe_priv, bg_color);
605 
606     if (status == VPE_STATUS_OK)
607         status = vpe_bg_color_outside_cs_gamut(vpe_priv, bg_color);
608 
609     return status;
610 }
611