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, °am_r, true);
439 compute_depq((double)bg_color->rgba.g, °am_g, true);
440 compute_depq((double)bg_color->rgba.b, °am_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, °am_r, true);
446 compute_degam(output_tf->tf, (double)bg_color->rgba.g, °am_g, true);
447 compute_degam(output_tf->tf, (double)bg_color->rgba.b, °am_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