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, °am_r, true);
442 compute_depq((double)bg_color->rgba.g, °am_g, true);
443 compute_depq((double)bg_color->rgba.b, °am_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, °am_r, true);
449 compute_degam(output_tf->tf, (double)bg_color->rgba.g, °am_g, true);
450 compute_degam(output_tf->tf, (double)bg_color->rgba.b, °am_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