1 // Unit tests for YCbCrConversionEffect. Mostly done by leveraging
2 // YCbCrInput and seeing that the right thing comes out at the
8 #include "effect_chain.h"
9 #include "gtest/gtest.h"
10 #include "image_format.h"
11 #include "test_util.h"
13 #include "ycbcr_input.h"
17 TEST(YCbCrConversionEffectTest, BasicInOut) {
21 // Pure-color test inputs, calculated with the formulas in Rec. 601
23 unsigned char y[width * height] = {
26 unsigned char cb[width * height] = {
27 128, 128, 90, 54, 240,
29 unsigned char cr[width * height] = {
30 128, 128, 240, 34, 110,
32 unsigned char expected_data[width * height * 4] = {
33 // The same data, just rearranged.
41 unsigned char out_data[width * height * 4];
43 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA8);
46 format.color_space = COLORSPACE_sRGB;
47 format.gamma_curve = GAMMA_sRGB;
49 YCbCrFormat ycbcr_format;
50 ycbcr_format.luma_coefficients = YCBCR_REC_601;
51 ycbcr_format.full_range = false;
52 ycbcr_format.num_levels = 256;
53 ycbcr_format.chroma_subsampling_x = 1;
54 ycbcr_format.chroma_subsampling_y = 1;
55 ycbcr_format.cb_x_position = 0.5f;
56 ycbcr_format.cb_y_position = 0.5f;
57 ycbcr_format.cr_x_position = 0.5f;
58 ycbcr_format.cr_y_position = 0.5f;
60 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format);
62 YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
63 input->set_pixel_data(0, y);
64 input->set_pixel_data(1, cb);
65 input->set_pixel_data(2, cr);
66 tester.get_chain()->add_input(input);
68 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
69 expect_equal(expected_data, out_data, 4 * width, height);
72 TEST(YCbCrConversionEffectTest, ClampToValidRange) {
76 // Some out-of-range of at-range values.
77 // Y should be clamped to 16-235 and Cb/Cr to 16-240.
78 // (Alpha should still be 255.)
79 unsigned char y[width * height] = {
80 0, 10, 16, 235, 240, 255
82 unsigned char cb[width * height] = {
83 0, 10, 16, 235, 240, 255,
85 unsigned char cr[width * height] = {
86 255, 240, 235, 16, 10, 0,
88 unsigned char expected_data[width * height * 4] = {
97 unsigned char out_data[width * height * 4];
99 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA8);
102 format.color_space = COLORSPACE_sRGB;
103 format.gamma_curve = GAMMA_sRGB;
105 YCbCrFormat ycbcr_format;
106 ycbcr_format.luma_coefficients = YCBCR_REC_601;
107 ycbcr_format.full_range = false;
108 ycbcr_format.num_levels = 256;
109 ycbcr_format.chroma_subsampling_x = 1;
110 ycbcr_format.chroma_subsampling_y = 1;
111 ycbcr_format.cb_x_position = 0.5f;
112 ycbcr_format.cb_y_position = 0.5f;
113 ycbcr_format.cr_x_position = 0.5f;
114 ycbcr_format.cr_y_position = 0.5f;
116 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format);
118 YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
119 input->set_pixel_data(0, y);
120 input->set_pixel_data(1, cb);
121 input->set_pixel_data(2, cr);
122 tester.get_chain()->add_input(input);
124 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
125 expect_equal(expected_data, out_data, 4 * width, height);
128 TEST(YCbCrConversionEffectTest, LimitedRangeToFullRange) {
130 const int height = 5;
132 // Pure-color test inputs, calculated with the formulas in Rec. 601
134 unsigned char y[width * height] = {
135 16, 235, 81, 145, 41,
137 unsigned char cb[width * height] = {
138 128, 128, 90, 54, 240,
140 unsigned char cr[width * height] = {
141 128, 128, 240, 34, 110,
143 unsigned char expected_data[width * height * 4] = {
144 // Range now from 0-255 for all components, and values in-between
145 // also adjusted a bit.
153 unsigned char out_data[width * height * 4];
155 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA8);
158 format.color_space = COLORSPACE_sRGB;
159 format.gamma_curve = GAMMA_sRGB;
161 YCbCrFormat ycbcr_format;
162 ycbcr_format.luma_coefficients = YCBCR_REC_601;
163 ycbcr_format.full_range = true;
164 ycbcr_format.num_levels = 256;
165 ycbcr_format.chroma_subsampling_x = 1;
166 ycbcr_format.chroma_subsampling_y = 1;
167 ycbcr_format.cb_x_position = 0.5f;
168 ycbcr_format.cb_y_position = 0.5f;
169 ycbcr_format.cr_x_position = 0.5f;
170 ycbcr_format.cr_y_position = 0.5f;
172 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format);
174 ycbcr_format.full_range = false;
175 YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
176 input->set_pixel_data(0, y);
177 input->set_pixel_data(1, cb);
178 input->set_pixel_data(2, cr);
179 tester.get_chain()->add_input(input);
181 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
183 // This specific data element has the correct value (110-128)*(255/224) + 128 = 107.509,
184 // which rounds the wrong way on some cards. In normal use, we detect this and round off
185 // in DitherEffect instead (so it's not a problem in pratice), but in unit tests like this,
186 // we don't run with dither, so we simply fudge this one value instead.
187 if (out_data[18] == 107) {
191 expect_equal(expected_data, out_data, 4 * width, height);
194 TEST(YCbCrConversionEffectTest, PlanarOutput) {
196 const int height = 5;
198 // Pure-color test inputs, calculated with the formulas in Rec. 601
200 unsigned char y[width * height] = {
201 16, 235, 81, 145, 41,
203 unsigned char cb[width * height] = {
204 128, 128, 90, 54, 240,
206 unsigned char cr[width * height] = {
207 128, 128, 240, 34, 110,
210 unsigned char out_y[width * height], out_cb[width * height], out_cr[width * height];
212 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA8);
215 format.color_space = COLORSPACE_sRGB;
216 format.gamma_curve = GAMMA_sRGB;
218 YCbCrFormat ycbcr_format;
219 ycbcr_format.luma_coefficients = YCBCR_REC_601;
220 ycbcr_format.full_range = false;
221 ycbcr_format.num_levels = 256;
222 ycbcr_format.chroma_subsampling_x = 1;
223 ycbcr_format.chroma_subsampling_y = 1;
224 ycbcr_format.cb_x_position = 0.5f;
225 ycbcr_format.cb_y_position = 0.5f;
226 ycbcr_format.cr_x_position = 0.5f;
227 ycbcr_format.cr_y_position = 0.5f;
229 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format, YCBCR_OUTPUT_PLANAR);
231 YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
232 input->set_pixel_data(0, y);
233 input->set_pixel_data(1, cb);
234 input->set_pixel_data(2, cr);
235 tester.get_chain()->add_input(input);
237 tester.run({out_y, out_cb, out_cr}, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
238 expect_equal(y, out_y, width, height);
239 expect_equal(cb, out_cb, width, height);
240 expect_equal(cr, out_cr, width, height);
243 TEST(YCbCrConversionEffectTest, SplitLumaAndChroma) {
245 const int height = 5;
247 // Pure-color test inputs, calculated with the formulas in Rec. 601
249 unsigned char y[width * height] = {
250 16, 235, 81, 145, 41,
252 unsigned char cb[width * height] = {
253 128, 128, 90, 54, 240,
255 unsigned char cr[width * height] = {
256 128, 128, 240, 34, 110,
259 // The R and A data, rearranged. Note: The G and B channels
260 // (the middle columns) are undefined. If we change the behavior,
261 // the test will need to be updated, but a failure is expected.
262 unsigned char expected_y[width * height * 4] = {
263 16, /*undefined:*/ 16, /*undefined:*/ 16, 255,
264 235, /*undefined:*/ 235, /*undefined:*/ 235, 255,
265 81, /*undefined:*/ 81, /*undefined:*/ 81, 255,
266 145, /*undefined:*/ 145, /*undefined:*/ 145, 255,
267 41, /*undefined:*/ 41, /*undefined:*/ 41, 255,
270 // Just the Cb and Cr data, rearranged. The B and A channels
271 // are undefined, as below.
272 unsigned char expected_cbcr[width * height * 4] = {
273 128, 128, /*undefined:*/ 128, /*undefined:*/ 255,
274 128, 128, /*undefined:*/ 128, /*undefined:*/ 255,
275 90, 240, /*undefined:*/ 240, /*undefined:*/ 255,
276 54, 34, /*undefined:*/ 34, /*undefined:*/ 255,
277 240, 110, /*undefined:*/ 110, /*undefined:*/ 255,
280 unsigned char out_y[width * height * 4], out_cbcr[width * height * 4];
282 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA8);
285 format.color_space = COLORSPACE_sRGB;
286 format.gamma_curve = GAMMA_sRGB;
288 YCbCrFormat ycbcr_format;
289 ycbcr_format.luma_coefficients = YCBCR_REC_601;
290 ycbcr_format.full_range = false;
291 ycbcr_format.num_levels = 256;
292 ycbcr_format.chroma_subsampling_x = 1;
293 ycbcr_format.chroma_subsampling_y = 1;
294 ycbcr_format.cb_x_position = 0.5f;
295 ycbcr_format.cb_y_position = 0.5f;
296 ycbcr_format.cr_x_position = 0.5f;
297 ycbcr_format.cr_y_position = 0.5f;
299 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format, YCBCR_OUTPUT_SPLIT_Y_AND_CBCR);
301 YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
302 input->set_pixel_data(0, y);
303 input->set_pixel_data(1, cb);
304 input->set_pixel_data(2, cr);
305 tester.get_chain()->add_input(input);
307 tester.run(std::vector<unsigned char *>{out_y, out_cbcr}, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
308 expect_equal(expected_y, out_y, width * 4, height);
309 expect_equal(expected_cbcr, out_cbcr, width * 4, height);
312 TEST(YCbCrConversionEffectTest, OutputChunkyAndRGBA) {
314 const int height = 5;
316 // Pure-color test inputs, calculated with the formulas in Rec. 601
318 unsigned char y[width * height] = {
319 16, 235, 81, 145, 41,
321 unsigned char cb[width * height] = {
322 128, 128, 90, 54, 240,
324 unsigned char cr[width * height] = {
325 128, 128, 240, 34, 110,
327 unsigned char expected_ycbcr[width * height * 4] = {
328 // The same data, just rearranged.
335 unsigned char expected_rgba[width * height * 4] = {
343 unsigned char out_ycbcr[width * height * 4];
344 unsigned char out_rgba[width * height * 4];
346 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA8);
349 format.color_space = COLORSPACE_sRGB;
350 format.gamma_curve = GAMMA_sRGB;
352 YCbCrFormat ycbcr_format;
353 ycbcr_format.luma_coefficients = YCBCR_REC_601;
354 ycbcr_format.full_range = false;
355 ycbcr_format.num_levels = 256;
356 ycbcr_format.chroma_subsampling_x = 1;
357 ycbcr_format.chroma_subsampling_y = 1;
358 ycbcr_format.cb_x_position = 0.5f;
359 ycbcr_format.cb_y_position = 0.5f;
360 ycbcr_format.cr_x_position = 0.5f;
361 ycbcr_format.cr_y_position = 0.5f;
363 tester.add_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
364 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format);
366 YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
367 input->set_pixel_data(0, y);
368 input->set_pixel_data(1, cb);
369 input->set_pixel_data(2, cr);
370 tester.get_chain()->add_input(input);
372 // Note: We don't test that the values actually get dithered,
373 // just that the shader compiles and doesn't mess up badly.
374 tester.get_chain()->set_dither_bits(8);
376 tester.run(std::vector<unsigned char *>{out_ycbcr, out_rgba}, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
377 expect_equal(expected_ycbcr, out_ycbcr, width * 4, height);
379 // Y'CbCr isn't 100% accurate (the input values are rounded),
380 // so we need some leeway.
381 expect_equal(expected_rgba, out_rgba, 4 * width, height, 7, 255 * 0.002);
384 TEST(YCbCrConversionEffectTest, MultipleOutputsAndRGBA) {
386 const int height = 5;
388 // Pure-color test inputs, calculated with the formulas in Rec. 601
390 unsigned char y[width * height] = {
391 16, 235, 81, 145, 41,
393 unsigned char cb[width * height] = {
394 128, 128, 90, 54, 240,
396 unsigned char cr[width * height] = {
397 128, 128, 240, 34, 110,
399 unsigned char expected_ycbcr[width * height * 4] = {
400 // The same data, just rearranged.
407 unsigned char expected_rgba[width * height * 4] = {
415 unsigned char out_ycbcr[width * height * 4];
416 unsigned char out_y[width * height * 4];
417 unsigned char out_cbcr[width * height * 4];
418 unsigned char out_rgba[width * height * 4];
420 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA8);
423 format.color_space = COLORSPACE_sRGB;
424 format.gamma_curve = GAMMA_sRGB;
426 YCbCrFormat ycbcr_format;
427 ycbcr_format.luma_coefficients = YCBCR_REC_601;
428 ycbcr_format.full_range = false;
429 ycbcr_format.num_levels = 256;
430 ycbcr_format.chroma_subsampling_x = 1;
431 ycbcr_format.chroma_subsampling_y = 1;
432 ycbcr_format.cb_x_position = 0.5f;
433 ycbcr_format.cb_y_position = 0.5f;
434 ycbcr_format.cr_x_position = 0.5f;
435 ycbcr_format.cr_y_position = 0.5f;
437 tester.add_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
438 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format);
439 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format, YCBCR_OUTPUT_SPLIT_Y_AND_CBCR);
441 YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
442 input->set_pixel_data(0, y);
443 input->set_pixel_data(1, cb);
444 input->set_pixel_data(2, cr);
445 tester.get_chain()->add_input(input);
447 // Note: We don't test that the values actually get dithered,
448 // just that the shader compiles and doesn't mess up badly.
449 tester.get_chain()->set_dither_bits(8);
451 tester.run({out_ycbcr, out_y, out_cbcr, out_rgba}, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
452 expect_equal(expected_ycbcr, out_ycbcr, width * 4, height);
454 // Check that the extra Y' and CbCr outputs also are fine.
455 for (unsigned i = 0; i < width * height; ++i) {
456 out_ycbcr[i * 4] = out_y[i * 4];
457 out_ycbcr[i * 4 + 1] = out_cbcr[i * 4 + 0];
458 out_ycbcr[i * 4 + 2] = out_cbcr[i * 4 + 1];
460 expect_equal(expected_ycbcr, out_ycbcr, width * 4, height);
462 // Y'CbCr isn't 100% accurate (the input values are rounded),
463 // so we need some leeway.
464 expect_equal(expected_rgba, out_rgba, 4 * width, height, 7, 255 * 0.002);
467 // Very similar to PlanarOutput.
468 TEST(YCbCrConversionEffectTest, ChangeOutputFormat) {
470 const int height = 5;
472 // Pure-color test inputs, calculated with the formulas in Rec. 601
474 unsigned char y[width * height] = {
475 16, 235, 81, 145, 41,
477 unsigned char cb[width * height] = {
478 128, 128, 90, 54, 240,
480 unsigned char cr[width * height] = {
481 128, 128, 240, 34, 110,
484 unsigned char out_y[width * height], out_cb[width * height], out_cr[width * height];
486 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA8);
489 format.color_space = COLORSPACE_sRGB;
490 format.gamma_curve = GAMMA_sRGB;
492 YCbCrFormat ycbcr_format;
493 ycbcr_format.luma_coefficients = YCBCR_REC_709; // Deliberately wrong at first.
494 ycbcr_format.full_range = false;
495 ycbcr_format.num_levels = 256;
496 ycbcr_format.chroma_subsampling_x = 1;
497 ycbcr_format.chroma_subsampling_y = 1;
498 ycbcr_format.cb_x_position = 0.5f;
499 ycbcr_format.cb_y_position = 0.5f;
500 ycbcr_format.cr_x_position = 0.5f;
501 ycbcr_format.cr_y_position = 0.5f;
503 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format, YCBCR_OUTPUT_PLANAR);
505 ycbcr_format.luma_coefficients = YCBCR_REC_601;
506 YCbCrInput *input = new YCbCrInput(format, ycbcr_format, width, height);
507 input->set_pixel_data(0, y);
508 input->set_pixel_data(1, cb);
509 input->set_pixel_data(2, cr);
510 tester.get_chain()->add_input(input);
512 tester.run({out_y, out_cb, out_cr}, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
514 // Now change the output format to match what we gave the input, and re-run.
515 tester.get_chain()->change_ycbcr_output_format(ycbcr_format);
516 tester.run({out_y, out_cb, out_cr}, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
518 expect_equal(y, out_y, width, height);
519 expect_equal(cb, out_cb, width, height);
520 expect_equal(cr, out_cr, width, height);
523 TEST(YCbCrConversionEffectTest, TenBitOutput) {
525 const int height = 5;
527 // Pure-color test inputs.
528 float data[width * height * 4] = {
529 0.0f, 0.0f, 0.0f, 1.0f,
530 1.0f, 1.0f, 1.0f, 1.0f,
531 1.0f, 0.0f, 0.0f, 1.0f,
532 0.0f, 1.0f, 0.0f, 1.0f,
533 0.0f, 0.0f, 1.0f, 1.0f,
535 uint32_t out_data[width * height];
536 int expanded_out_data[width * height * 4];
537 int expected_data[width * height * 4] = {
538 // Expected results, calculated using formulas 3.2, 3.3 and 3.4
539 // from Rec. 709. (Except the first two, which are obvious
540 // given the 64–940 range of luminance.)
548 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGB10_A2);
549 tester.add_input(data, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_sRGB);
552 format.color_space = COLORSPACE_sRGB;
553 format.gamma_curve = GAMMA_sRGB;
555 YCbCrFormat ycbcr_format;
556 ycbcr_format.luma_coefficients = YCBCR_REC_709;
557 ycbcr_format.full_range = false;
558 ycbcr_format.num_levels = 1024;
559 ycbcr_format.chroma_subsampling_x = 1;
560 ycbcr_format.chroma_subsampling_y = 1;
561 ycbcr_format.cb_x_position = 0.5f;
562 ycbcr_format.cb_y_position = 0.5f;
563 ycbcr_format.cr_x_position = 0.5f;
564 ycbcr_format.cr_y_position = 0.5f;
566 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format);
567 tester.run_10_10_10_2(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
569 // Unpack 10:10:10:2 to 32:32:32:32.
570 for (unsigned i = 0; i < width * height; ++i) {
571 expanded_out_data[i * 4 + 0] = out_data[i] & 0x3ff;
572 expanded_out_data[i * 4 + 1] = (out_data[i] >> 10) & 0x3ff;
573 expanded_out_data[i * 4 + 2] = (out_data[i] >> 20) & 0x3ff;
574 expanded_out_data[i * 4 + 3] = (out_data[i] >> 30);
576 expect_equal(expected_data, expanded_out_data, 4 * width, height);
579 TEST(YCbCrConversionEffectTest, TenBitOutputInSixteen) {
581 const int height = 5;
583 // Same test inputs and outputs as TenBitOutput, except that alpha
584 // is 16 bits instead of two.
585 float data[width * height * 4] = {
586 0.0f, 0.0f, 0.0f, 1.0f,
587 1.0f, 1.0f, 1.0f, 1.0f,
588 1.0f, 0.0f, 0.0f, 1.0f,
589 0.0f, 1.0f, 0.0f, 1.0f,
590 0.0f, 0.0f, 1.0f, 1.0f,
592 uint16_t out_data[width * height * 4];
593 uint16_t expected_data[width * height * 4] = {
595 940, 512, 512, 65535,
596 250, 409, 960, 65535,
597 691, 167, 105, 65535,
598 127, 960, 471, 65535,
601 EffectChainTester tester(nullptr, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA16);
602 tester.add_input(data, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_sRGB);
605 format.color_space = COLORSPACE_sRGB;
606 format.gamma_curve = GAMMA_sRGB;
608 YCbCrFormat ycbcr_format;
609 ycbcr_format.luma_coefficients = YCBCR_REC_709;
610 ycbcr_format.full_range = false;
611 ycbcr_format.num_levels = 1024;
612 ycbcr_format.chroma_subsampling_x = 1;
613 ycbcr_format.chroma_subsampling_y = 1;
614 ycbcr_format.cb_x_position = 0.5f;
615 ycbcr_format.cb_y_position = 0.5f;
616 ycbcr_format.cr_x_position = 0.5f;
617 ycbcr_format.cr_y_position = 0.5f;
619 tester.add_ycbcr_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format, YCBCR_OUTPUT_INTERLEAVED, GL_UNSIGNED_SHORT);
620 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_sRGB);
622 // Add some slight leeway for the benefit of cards that don't
623 // round correctly (would be fixed by DitherEffect if we had dither).
624 expect_equal(expected_data, out_data, 4 * width, height, 2);