1 #include <algorithm>
2 #include <cstdio>
3 #include <string>
4 #include <vector>
5 #include "colorspace/colorspace.h"
6 #include "common/pixel.h"
7 #include "depth/depth.h"
8 #include "graph/filtergraph.h"
9 #include "graph/graphbuilder.h"
10 #include "resize/resize.h"
11 #include "unresize/unresize.h"
12 
13 #include "gtest/gtest.h"
14 
15 namespace {
16 
17 using zimg::colorspace::MatrixCoefficients;
18 using zimg::colorspace::TransferCharacteristics;
19 using zimg::colorspace::ColorPrimaries;
20 using zimg::graph::GraphBuilder;
21 
22 typedef std::vector<std::string> TraceList;
23 
24 class TracingObserver : public zimg::graph::FilterObserver {
25 	TraceList m_trace;
26 public:
trace() const27 	const TraceList &trace() const { return m_trace; }
28 
yuv_to_grey()29 	void yuv_to_grey() override { m_trace.push_back("yuv_to_grey"); }
30 
grey_to_yuv()31 	void grey_to_yuv() override { m_trace.push_back("grey_to_yuv"); }
grey_to_rgb()32 	void grey_to_rgb() override { m_trace.push_back("grey_to_rgb"); }
33 
premultiply()34 	void premultiply() override { m_trace.push_back("premultiply"); }
unpremultiply()35 	void unpremultiply() override { m_trace.push_back("unpremultiply"); }
add_opaque()36 	void add_opaque() override { m_trace.push_back("add_opaque"); }
discard_alpha()37 	void discard_alpha() override { m_trace.push_back("discard_alpha"); }
38 
colorspace(const zimg::colorspace::ColorspaceConversion & conv)39 	void colorspace(const zimg::colorspace::ColorspaceConversion &conv) override
40 	{
41 		char buffer[128];
42 		sprintf(buffer, "colorspace: [%d, %d, %d] => [%d, %d, %d] (%f)\n",
43 			static_cast<int>(conv.csp_in.matrix),
44 			static_cast<int>(conv.csp_in.transfer),
45 			static_cast<int>(conv.csp_in.primaries),
46 			static_cast<int>(conv.csp_out.matrix),
47 			static_cast<int>(conv.csp_out.transfer),
48 			static_cast<int>(conv.csp_out.primaries),
49 			conv.peak_luminance);
50 		m_trace.push_back(buffer);
51 	}
52 
depth(const zimg::depth::DepthConversion & conv,int plane)53 	void depth(const zimg::depth::DepthConversion &conv, int plane) override
54 	{
55 		char buffer[128];
56 		sprintf(buffer, "depth[%d]: [%d/%u %c:%c%s] => [%d/%u %c:%c%s]\n",
57 			plane,
58 			static_cast<int>(conv.pixel_in.type),
59 			conv.pixel_in.depth,
60 			conv.pixel_in.fullrange ? 'f' : 'l',
61 			conv.pixel_in.chroma ? 'c' : 'l',
62 			conv.pixel_in.ycgco ? " ycgco" : "",
63 			static_cast<int>(conv.pixel_out.type),
64 			conv.pixel_out.depth,
65 			conv.pixel_out.fullrange ? 'f' : 'l',
66 			conv.pixel_out.chroma ? 'c' : 'l',
67 			conv.pixel_out.ycgco ? " ycgco" : "");
68 		m_trace.push_back(buffer);
69 	}
70 
resize(const zimg::resize::ResizeConversion & conv,int plane)71 	void resize(const zimg::resize::ResizeConversion &conv, int plane) override
72 	{
73 		char buffer[128];
74 		sprintf(buffer, "resize[%d]: [%u, %u] => [%u, %u] (%f, %f, %f, %f)\n",
75 			plane,
76 			conv.src_width,
77 			conv.src_height,
78 			conv.dst_width,
79 			conv.dst_height,
80 			conv.shift_w,
81 			conv.shift_h,
82 			conv.subwidth,
83 			conv.subheight);
84 		m_trace.push_back(buffer);
85 	}
86 
unresize(const zimg::unresize::UnresizeConversion & conv,int plane)87 	void unresize(const zimg::unresize::UnresizeConversion &conv, int plane) override
88 	{
89 		char buffer[128];
90 		sprintf(buffer, "unresize: [%u, %u] => [%u, %u] (%f, %f)\n",
91 			conv.up_width,
92 			conv.up_height,
93 			conv.orig_width,
94 			conv.orig_height,
95 			conv.shift_w,
96 			conv.shift_h);
97 		m_trace.push_back(buffer);
98 	}
99 };
100 
101 
make_basic_rgb_state()102 GraphBuilder::state make_basic_rgb_state()
103 {
104 	GraphBuilder::state state{};
105 	state.width = 64;
106 	state.height = 48;
107 	state.type = zimg::PixelType::FLOAT;
108 	state.subsample_w = 0;
109 	state.subsample_h = 0;
110 	state.color = GraphBuilder::ColorFamily::RGB;
111 	state.colorspace = { MatrixCoefficients::RGB, TransferCharacteristics::REC_709, ColorPrimaries::REC_709 };
112 	state.depth = zimg::pixel_depth(zimg::PixelType::FLOAT);
113 	state.fullrange = false;
114 	state.parity = GraphBuilder::FieldParity::PROGRESSIVE;
115 	state.chroma_location_w = GraphBuilder::ChromaLocationW::CENTER;
116 	state.chroma_location_h = GraphBuilder::ChromaLocationH::CENTER;
117 	state.active_left = 0.0;
118 	state.active_top = 0.0;
119 	state.active_width = 64.0;
120 	state.active_height = 48.0;
121 	state.alpha = GraphBuilder::AlphaType::NONE;
122 	return state;
123 }
124 
make_basic_yuv_state()125 GraphBuilder::state make_basic_yuv_state()
126 {
127 	GraphBuilder::state state = make_basic_rgb_state();
128 	state.color = GraphBuilder::ColorFamily::YUV;
129 	state.colorspace = { MatrixCoefficients::REC_709, TransferCharacteristics::REC_709, ColorPrimaries::REC_709 };
130 	return state;
131 }
132 
set_resolution(GraphBuilder::state & state,unsigned width,unsigned height)133 void set_resolution(GraphBuilder::state &state, unsigned width, unsigned height)
134 {
135 	state.width = width;
136 	state.height = height;
137 	state.active_left = 0;
138 	state.active_top = 0;
139 	state.active_width = width;
140 	state.active_height = height;
141 }
142 
test_case(const GraphBuilder::state & source,const GraphBuilder::state & target,const TraceList & trace)143 void test_case(const GraphBuilder::state &source, const GraphBuilder::state &target, const TraceList &trace)
144 {
145 	GraphBuilder builder;
146 	TracingObserver observer;
147 	builder.set_source(source).connect(target, nullptr, &observer).complete();
148 
149 	EXPECT_EQ(trace.size(), observer.trace().size());
150 	for (size_t i = 0; i < std::min(trace.size(), observer.trace().size()); ++i) {
151 		EXPECT_TRUE(observer.trace()[i].rfind(trace[i]) == 0)
152 			<< "Expected: " << trace[i] << "\nActual: " << observer.trace()[i];
153 	}
154 	for (size_t i = std::min(trace.size(), observer.trace().size()); i < observer.trace().size(); ++i) {
155 		ADD_FAILURE() << "Unexpected[" << i << "]: " << observer.trace()[i];
156 	}
157 }
158 
159 } // namespace
160 
161 
TEST(GraphBuilderTest,test_noop)162 TEST(GraphBuilderTest, test_noop)
163 {
164 	auto source = make_basic_rgb_state();
165 	auto target = source;
166 	test_case(source, target, {});
167 }
168 
TEST(GraphBuilderTest,test_resize_only_rgb)169 TEST(GraphBuilderTest, test_resize_only_rgb)
170 {
171 	auto source = make_basic_rgb_state();
172 	set_resolution(source, 64, 48);
173 
174 	auto target = source;
175 	set_resolution(target, 128, 96);
176 
177 	test_case(source, target, { "resize[0]: [64, 48] => [128, 96]" });
178 }
179 
TEST(GraphBuilderTest,test_resize_only_444)180 TEST(GraphBuilderTest, test_resize_only_444)
181 {
182 	auto source = make_basic_yuv_state();
183 	set_resolution(source, 64, 48);
184 
185 	auto target = source;
186 	set_resolution(target, 128, 96);
187 
188 	test_case(source, target, {
189 		"resize[0]: [64, 48] => [128, 96]",
190 		"resize[1]: [64, 48] => [128, 96]",
191 	});
192 }
193 
TEST(GraphBuilderTest,test_resize_only_420)194 TEST(GraphBuilderTest, test_resize_only_420)
195 {
196 	auto source = make_basic_yuv_state();
197 	set_resolution(source, 64, 48);
198 	source.subsample_w = 1;
199 	source.subsample_h = 1;
200 
201 	auto target = source;
202 	set_resolution(target, 128, 96);
203 
204 	test_case(source, target, {
205 		"resize[0]: [64, 48] => [128, 96]",
206 		"resize[1]: [32, 24] => [64, 48]"
207 	});
208 }
209 
TEST(GraphBuilderTest,test_resize_420_to_444)210 TEST(GraphBuilderTest, test_resize_420_to_444)
211 {
212 	auto source = make_basic_yuv_state();
213 	source.subsample_w = 1;
214 	source.subsample_h = 1;
215 
216 	auto target = make_basic_yuv_state();
217 
218 	test_case(source, target, { "resize[1]" });
219 }
220 
TEST(GraphBuilderTest,test_resize_444_to_420)221 TEST(GraphBuilderTest, test_resize_444_to_420)
222 {
223 	auto source = make_basic_yuv_state();
224 
225 	auto target = make_basic_yuv_state();
226 	target.subsample_w = 1;
227 	target.subsample_h = 1;
228 
229 	test_case(source, target, { "resize[1]" });
230 }
231 
TEST(GraphBuilderTest,test_resize_chromaloc_upsample)232 TEST(GraphBuilderTest, test_resize_chromaloc_upsample)
233 {
234 	auto source = make_basic_yuv_state();
235 	set_resolution(source, 64, 48);
236 	source.subsample_w = 1;
237 	source.subsample_h = 1;
238 	source.chroma_location_w = GraphBuilder::ChromaLocationW::LEFT;
239 	source.chroma_location_h = GraphBuilder::ChromaLocationH::BOTTOM;
240 
241 	auto target = make_basic_yuv_state();
242 	set_resolution(target, 64, 48);
243 
244 	test_case(source, target, { "resize[1]: [32, 24] => [64, 48] (0.250000, -0.250000, 32.000000, 24.000000)" });
245 }
246 
TEST(GraphBuilderTest,test_resize_chromaloc_downsample)247 TEST(GraphBuilderTest, test_resize_chromaloc_downsample)
248 {
249 	auto source = make_basic_yuv_state();
250 	set_resolution(source, 64, 48);
251 
252 	auto target = make_basic_yuv_state();
253 	set_resolution(target, 64, 48);
254 	target.subsample_w = 1;
255 	target.subsample_h = 1;
256 	target.chroma_location_w = GraphBuilder::ChromaLocationW::LEFT;
257 	target.chroma_location_h = GraphBuilder::ChromaLocationH::BOTTOM;
258 
259 	test_case(source, target, { "resize[1]: [64, 48] => [32, 24] (-0.500000, 0.500000, 64.000000, 48.000000)" });
260 }
261 
TEST(GraphBuilderTest,test_resize_deinterlace)262 TEST(GraphBuilderTest, test_resize_deinterlace)
263 {
264 	auto source = make_basic_yuv_state();
265 	set_resolution(source, 64, 48);
266 	source.subsample_h = 1;
267 
268 	auto target = make_basic_yuv_state();
269 	set_resolution(target, 64, 48);
270 	target.subsample_h = 1;
271 	target.parity = GraphBuilder::FieldParity::PROGRESSIVE;
272 
273 	source.parity = GraphBuilder::FieldParity::TOP;
274 	test_case(source, target, {
275 		"resize[0]: [64, 48] => [64, 48] (0.000000, 0.250000, 64.000000, 48.000000)",
276 		"resize[1]: [64, 24] => [64, 24] (0.000000, 0.250000, 64.000000, 24.000000)",
277 	});
278 
279 	source.parity = GraphBuilder::FieldParity::BOTTOM;
280 	test_case(source, target, {
281 		"resize[0]: [64, 48] => [64, 48] (0.000000, -0.250000, 64.000000, 48.000000)",
282 		"resize[1]: [64, 24] => [64, 24] (0.000000, -0.250000, 64.000000, 24.000000)",
283 	});
284 }
285 
TEST(GraphBuilderTest,test_resize_interlace_to_interlace)286 TEST(GraphBuilderTest, test_resize_interlace_to_interlace)
287 {
288 	auto source = make_basic_yuv_state();
289 	set_resolution(source, 64, 48);
290 	source.subsample_w = 1;
291 	source.subsample_h = 1;
292 	source.parity = GraphBuilder::FieldParity::TOP;
293 	source.chroma_location_w = GraphBuilder::ChromaLocationW::LEFT;
294 	source.chroma_location_h = GraphBuilder::ChromaLocationH::BOTTOM;
295 
296 	auto target = make_basic_yuv_state();
297 	set_resolution(target, 64, 96);
298 	target.subsample_w = 1;
299 	target.subsample_h = 1;
300 	target.parity = GraphBuilder::FieldParity::TOP;
301 	target.chroma_location_w = GraphBuilder::ChromaLocationW::LEFT;
302 	target.chroma_location_h = GraphBuilder::ChromaLocationH::BOTTOM;
303 
304 	test_case(source, target, {
305 		"resize[0]: [64, 48] => [64, 96] (0.000000, 0.125000, 64.000000, 48.000000)",
306 		"resize[1]: [32, 24] => [32, 48] (0.000000, 0.062500, 32.000000, 24.000000)",
307 	});
308 }
309 
TEST(GraphBuilderTest,test_resize_byte_fast_path)310 TEST(GraphBuilderTest, test_resize_byte_fast_path)
311 {
312 	auto source = make_basic_rgb_state();
313 	source.type = zimg::PixelType::BYTE;
314 	source.depth = 8;
315 	source.fullrange = true;
316 	set_resolution(source, 64, 48);
317 
318 	auto target = source;
319 	set_resolution(target, 128, 96);
320 
321 	test_case(source, target, {
322 		"depth[0]: [0/8 l:l] => [1/16 l:l]",
323 		"resize",
324 		"depth[0]: [1/16 l:l] => [0/8 l:l]",
325 	});
326 }
327 
TEST(GraphBuilderTest,test_resize_byte_slow_path)328 TEST(GraphBuilderTest, test_resize_byte_slow_path)
329 {
330 	auto source = make_basic_rgb_state();
331 	source.type = zimg::PixelType::BYTE;
332 	source.depth = 8;
333 	source.fullrange = true;
334 	set_resolution(source, 64, 48);
335 
336 	auto target = source;
337 	target.fullrange = false;
338 	set_resolution(target, 128, 96);
339 
340 	test_case(source, target, {
341 		"depth[0]: [0/8 f:l] => [3/32 l:l]",
342 		"resize",
343 		"depth[0]: [3/32 l:l] => [0/8 l:l]",
344 		});
345 }
346 
TEST(GraphBuilderTest,test_resize_byte_word)347 TEST(GraphBuilderTest, test_resize_byte_word)
348 {
349 	auto source = make_basic_yuv_state();
350 	source.type = zimg::PixelType::BYTE;
351 	source.depth = 8;
352 	source.fullrange = true;
353 	source.colorspace.matrix = MatrixCoefficients::YCGCO;
354 	set_resolution(source, 64, 48);
355 
356 	auto target = source;
357 	target.type = zimg::PixelType::WORD;
358 	target.depth = 10;
359 	target.fullrange = false;
360 	set_resolution(target, 128, 96);
361 
362 	test_case(source, target, {
363 		"depth[0]: [0/8 f:l ycgco] => [1/10 l:l ycgco]",
364 		"resize[0]",
365 		"depth[1]: [0/8 f:c ycgco] => [1/10 l:c ycgco]",
366 		"resize[1]",
367 	});
368 }
369 
TEST(GraphBuilderTest,test_resize_word_byte)370 TEST(GraphBuilderTest, test_resize_word_byte)
371 {
372 	auto source = make_basic_yuv_state();
373 	source.type = zimg::PixelType::WORD;
374 	source.depth = 10;
375 	source.fullrange = false;
376 	source.colorspace.matrix = MatrixCoefficients::YCGCO;
377 	set_resolution(source, 64, 48);
378 
379 	auto target = source;
380 	target.type = zimg::PixelType::BYTE;
381 	target.depth = 8;
382 	target.fullrange = true;
383 	set_resolution(target, 128, 96);
384 
385 	test_case(source, target, {
386 		"resize[0]",
387 		"depth[0]: [1/10 l:l ycgco] => [0/8 f:l ycgco]",
388 		"resize[1]",
389 		"depth[1]: [1/10 l:c ycgco] => [0/8 f:c ycgco]",
390 	});
391 }
392 
TEST(GraphBuilderTest,test_colorspace_only)393 TEST(GraphBuilderTest, test_colorspace_only)
394 {
395 	auto source = make_basic_rgb_state();
396 	auto target = make_basic_yuv_state();
397 	test_case(source, target, { "colorspace" });
398 }
399 
TEST(GraphBuilderTest,test_upscale_colorspace)400 TEST(GraphBuilderTest, test_upscale_colorspace)
401 {
402 	auto source = make_basic_yuv_state();
403 	set_resolution(source, 64, 48);
404 	source.subsample_w = 1;
405 	source.subsample_h = 1;
406 
407 	auto target = source;
408 	set_resolution(target, 96, 72);
409 	target.colorspace = { MatrixCoefficients::REC_2020_NCL, TransferCharacteristics::REC_709, ColorPrimaries::REC_2020 };
410 
411 	test_case(source, target, {
412 		"resize[1]: [32, 24] => [64, 48]",
413 		"colorspace",
414 		"resize[0]: [64, 48] => [96, 72]",
415 		"resize[1]: [64, 48] => [48, 36]",
416 	});
417 }
418 
TEST(GraphBuilderTest,test_downscale_colorspace)419 TEST(GraphBuilderTest, test_downscale_colorspace)
420 {
421 	auto source = make_basic_yuv_state();
422 	set_resolution(source, 96, 72);
423 	source.subsample_w = 1;
424 	source.subsample_h = 1;
425 
426 	auto target = source;
427 	set_resolution(target, 64, 48);
428 	target.colorspace = { MatrixCoefficients::REC_2020_NCL, TransferCharacteristics::REC_709, ColorPrimaries::REC_2020 };
429 
430 	test_case(source, target, {
431 		"resize[0]: [96, 72] => [64, 48]",
432 		"resize[1]: [48, 36] => [64, 48]",
433 		"colorspace",
434 		"resize[1]: [64, 48] => [32, 24]",
435 	});
436 }
437 
TEST(GraphBuilderTest,test_upscale_colorspace_tile)438 TEST(GraphBuilderTest, test_upscale_colorspace_tile)
439 {
440 	auto source = make_basic_yuv_state();
441 	set_resolution(source, 64, 48);
442 	source.subsample_w = 1;
443 	source.subsample_h = 1;
444 	source.active_left = 32;
445 	source.active_top = 24;
446 	source.active_width = 32;
447 	source.active_height = 24;
448 
449 	auto target = make_basic_rgb_state();
450 	set_resolution(target, 48, 36);
451 
452 	test_case(source, target, {
453 		"resize[0]: [64, 48] => [48, 36] (32.000000, 24.000000, 32.000000, 24.000000)",
454 		"resize[1]: [32, 24] => [48, 36] (16.000000, 12.000000, 16.000000, 12.000000)",
455 		"colorspace",
456 	});
457 }
458 
TEST(GraphBuilderTest,test_downscale_colorspace_tile)459 TEST(GraphBuilderTest, test_downscale_colorspace_tile)
460 {
461 	auto source = make_basic_rgb_state();
462 	set_resolution(source, 96, 72);
463 	source.active_left = 48;
464 	source.active_top = 36;
465 	source.active_width = 48;
466 	source.active_height = 36;
467 
468 	auto target = make_basic_yuv_state();
469 	set_resolution(target, 32, 24);
470 	target.subsample_w = 1;
471 	target.subsample_h = 1;
472 
473 	test_case(source, target, {
474 		"resize[0]: [96, 72] => [32, 24] (48.000000, 36.000000, 48.000000, 36.000000)",
475 		"colorspace",
476 		"resize[1]: [32, 24] => [16, 12] (0.000000, 0.000000, 32.000000, 24.000000)",
477 	});
478 }
479 
TEST(GraphBuilderTest,test_grey_to_grey_noop)480 TEST(GraphBuilderTest, test_grey_to_grey_noop)
481 {
482 	auto source = make_basic_yuv_state();
483 	source.color = GraphBuilder::ColorFamily::GREY;
484 	source.colorspace = { MatrixCoefficients::REC_709, TransferCharacteristics::REC_709, ColorPrimaries::REC_709 };
485 
486 	auto target = source;
487 	target.colorspace = { MatrixCoefficients::REC_601, TransferCharacteristics::REC_709, ColorPrimaries::REC_709 };
488 
489 	test_case(source, target, {});
490 }
491 
TEST(GraphBuilderTest,test_grey_to_rgb_noop)492 TEST(GraphBuilderTest, test_grey_to_rgb_noop)
493 {
494 	auto source = make_basic_yuv_state();
495 	source.color = GraphBuilder::ColorFamily::GREY;
496 	source.colorspace.matrix = MatrixCoefficients::REC_2020_CL;
497 
498 	auto target = make_basic_rgb_state();
499 	target.colorspace.matrix = MatrixCoefficients::UNSPECIFIED;
500 
501 	test_case(source, target, { "grey_to_rgb" });
502 }
503 
TEST(GraphBuilderTest,test_grey_to_yuv_noop)504 TEST(GraphBuilderTest, test_grey_to_yuv_noop)
505 {
506 	auto source = make_basic_yuv_state();
507 	source.color = GraphBuilder::ColorFamily::GREY;
508 	source.colorspace.matrix = MatrixCoefficients::UNSPECIFIED;
509 
510 	auto target = make_basic_yuv_state();
511 	target.colorspace.matrix = MatrixCoefficients::REC_2020_CL;
512 
513 	test_case(source, target, { "grey_to_yuv" });
514 }
515 
TEST(GraphBuilderTest,test_grey_to_grey_colorspace)516 TEST(GraphBuilderTest, test_grey_to_grey_colorspace)
517 {
518 	auto source = make_basic_yuv_state();
519 	source.color = GraphBuilder::ColorFamily::GREY;
520 	source.colorspace = { MatrixCoefficients::REC_709, TransferCharacteristics::REC_709, ColorPrimaries::DCI_P3 };
521 
522 	auto target = source;
523 	target.colorspace = { MatrixCoefficients::REC_601, TransferCharacteristics::REC_709, ColorPrimaries::SMPTE_C };
524 
525 	test_case(source, target, {
526 		"grey_to_rgb",
527 		"colorspace",
528 		"yuv_to_grey",
529 		});
530 }
531 
TEST(GraphBuilderTest,test_yuv_to_grey_colorspace)532 TEST(GraphBuilderTest, test_yuv_to_grey_colorspace)
533 {
534 	auto source = make_basic_yuv_state();
535 	source.colorspace = { MatrixCoefficients::REC_709, TransferCharacteristics::REC_709, ColorPrimaries::DCI_P3 };
536 
537 	auto target = source;
538 	target.color = GraphBuilder::ColorFamily::GREY;
539 	target.colorspace = { MatrixCoefficients::REC_601, TransferCharacteristics::REC_709, ColorPrimaries::SMPTE_C };
540 
541 	test_case(source, target, {
542 		"colorspace",
543 		"yuv_to_grey",
544 	});
545 }
546 
TEST(GraphBuilderTest,test_straight_to_premul)547 TEST(GraphBuilderTest, test_straight_to_premul)
548 {
549 	auto source = make_basic_yuv_state();
550 	source.subsample_w = 1;
551 	source.subsample_h = 1;
552 	source.alpha = GraphBuilder::AlphaType::STRAIGHT;
553 
554 	auto target = source;
555 	target.alpha = GraphBuilder::AlphaType::PREMULTIPLIED;
556 
557 	test_case(source, target, {
558 		"resize[1]",
559 		"premultiply",
560 		"resize[1]",
561 	});
562 }
563 
TEST(GraphBuilderTest,test_premul_to_straight)564 TEST(GraphBuilderTest, test_premul_to_straight)
565 {
566 	auto source = make_basic_yuv_state();
567 	source.subsample_w = 1;
568 	source.subsample_h = 1;
569 	source.alpha = GraphBuilder::AlphaType::PREMULTIPLIED;
570 
571 	auto target = source;
572 	target.alpha = GraphBuilder::AlphaType::STRAIGHT;
573 
574 	test_case(source, target, {
575 		"resize[1]",
576 		"unpremultiply",
577 		"resize[1]",
578 	});
579 }
580 
TEST(GraphBuilderTest,test_straight_to_opaque)581 TEST(GraphBuilderTest, test_straight_to_opaque)
582 {
583 	auto source = make_basic_rgb_state();
584 	source.alpha = GraphBuilder::AlphaType::STRAIGHT;
585 
586 	auto target = source;
587 	target.alpha = GraphBuilder::AlphaType::NONE;
588 
589 	test_case(source, target, { "premultiply", "discard_alpha" });
590 }
591 
TEST(GraphBuilderTest,test_opaque_to_straight)592 TEST(GraphBuilderTest, test_opaque_to_straight)
593 {
594 	auto source = make_basic_rgb_state();
595 	source.alpha = GraphBuilder::AlphaType::NONE;
596 
597 	auto target = make_basic_yuv_state();
598 	target.alpha = GraphBuilder::AlphaType::STRAIGHT;
599 
600 	test_case(source, target, { "colorspace", "add_opaque" });
601 }
602 
TEST(GraphBuilderTest,test_colorspace_straight_alpha)603 TEST(GraphBuilderTest, test_colorspace_straight_alpha)
604 {
605 	auto source = make_basic_yuv_state();
606 	source.subsample_w = 1;
607 	source.subsample_h = 1;
608 	source.alpha = GraphBuilder::AlphaType::STRAIGHT;
609 
610 	auto target = make_basic_rgb_state();
611 	target.alpha = GraphBuilder::AlphaType::STRAIGHT;
612 
613 	test_case(source, target, {
614 		"resize[1]",
615 		"premultiply",
616 		"colorspace",
617 		"unpremultiply",
618 	});
619 }
620 
TEST(GraphBuilderTest,test_resize_straight_alpha)621 TEST(GraphBuilderTest, test_resize_straight_alpha)
622 {
623 	auto source = make_basic_rgb_state();
624 	set_resolution(source, 64, 48);
625 	source.alpha = GraphBuilder::AlphaType::STRAIGHT;
626 
627 	auto target = source;
628 	set_resolution(target, 128, 96);
629 
630 	test_case(source, target, {
631 		"premultiply",
632 		"resize[0]: [64, 48] => [128, 96]",
633 		"resize[3]: [64, 48] => [128, 96]",
634 		"unpremultiply",
635 	});
636 }
637 
TEST(GraphBuilderTest,test_resize_premul_alpha)638 TEST(GraphBuilderTest, test_resize_premul_alpha)
639 {
640 	auto source = make_basic_rgb_state();
641 	set_resolution(source, 64, 48);
642 	source.alpha = GraphBuilder::AlphaType::PREMULTIPLIED;
643 
644 	auto target = source;
645 	set_resolution(target, 128, 96);
646 
647 	test_case(source, target, {
648 		"resize[0]: [64, 48] => [128, 96]",
649 		"resize[3]: [64, 48] => [128, 96]",
650 	});
651 }
652 
TEST(GraphBuilderTest,test_straight_depth)653 TEST(GraphBuilderTest, test_straight_depth)
654 {
655 	auto source = make_basic_yuv_state();
656 	set_resolution(source, 64, 48);
657 	source.alpha = GraphBuilder::AlphaType::STRAIGHT;
658 
659 	auto target = source;
660 	target.type = zimg::PixelType::WORD;
661 	target.depth = 16;
662 
663 	test_case(source, target, {
664 		"depth[0]: [3/32 l:l] => [1/16 l:l]",
665 		"depth[1]: [3/32 l:c] => [1/16 l:c]",
666 		"depth[3]: [3/32 l:l] => [1/16 f:l]",
667 	});
668 }
669 
TEST(GraphBuilderTest,test_straight_depth_tile)670 TEST(GraphBuilderTest, test_straight_depth_tile)
671 {
672 	auto source = make_basic_yuv_state();
673 	set_resolution(source, 64, 48);
674 	source.alpha = GraphBuilder::AlphaType::STRAIGHT;
675 	source.active_width = 32;
676 	source.active_height = 24;
677 
678 	auto target = source;
679 	set_resolution(target, 32, 24);
680 	target.type = zimg::PixelType::WORD;
681 	target.depth = 16;
682 
683 	test_case(source, target, {
684 		"resize[0]: [64, 48] => [32, 24] (0.000000, 0.000000, 32.000000, 24.000000)",
685 		"depth[0]: [3/32 l:l] => [1/16 l:l]",
686 		"resize[1]: [64, 48] => [32, 24] (0.000000, 0.000000, 32.000000, 24.000000)",
687 		"depth[1]: [3/32 l:c] => [1/16 l:c]",
688 		"resize[3]: [64, 48] => [32, 24] (0.000000, 0.000000, 32.000000, 24.000000)",
689 		"depth[3]: [3/32 l:l] => [1/16 f:l]",
690 	});
691 }
692