4407 {
4409 std::stringstream desc_str;
4411 desc_str << "blend[" << mode_string << ", " << color << "]";
4412 std::string desc = desc_str.str();
4413 DlBlendColorFilter filter(color, mode);
4414 if (filter.modifies_transparent_black()) {
4415 ASSERT_NE(DlColorFilter::MakeBlend(color, mode), nullptr) << desc;
4416 }
4417
4420
4421 DisplayListBuilder builder1;
4423 builder1.Rotate(45);
4425 builder1.DrawRect(kRenderBounds, paint);
4426 auto display_list1 = builder1.Build();
4427
4428 DisplayListBuilder builder2;
4430 builder2.Rotate(45);
4432 builder2.SaveLayer(kTestBounds2, &filter_save_paint);
4433 builder2.DrawRect(kRenderBounds, paint);
4434 builder2.Restore();
4435 auto display_list2 = builder2.Build();
4436
4437 for (auto& back_end : CanvasCompareTester::TestBackends) {
4438 auto provider = CanvasCompareTester::GetProvider(back_end);
4439 auto env = std::make_unique<RenderEnvironment>(
4440 provider.get(), PixelFormat::kN32PremulPixelFormat);
4441 auto results1 = env->getResult(display_list1);
4442 auto results2 = env->getResult(display_list2);
4443 int modified_transparent_pixels =
4444 CanvasCompareTester::countModifiedTransparentPixels(results1.get(),
4445 results2.get());
4446 EXPECT_EQ(filter.modifies_transparent_black(),
4447 modified_transparent_pixels != 0)
4448 << desc;
4449 }
4450 };
4451
4453 test_mode_color(mode, DlColor::kTransparent());
4454 test_mode_color(mode, DlColor::kWhite());
4455 test_mode_color(mode, DlColor::kWhite().modulateOpacity(0.5));
4456 test_mode_color(mode, DlColor::kBlack());
4457 test_mode_color(mode, DlColor::kBlack().modulateOpacity(0.5));
4458 };
4459
4460#define TEST_MODE(V) test_mode(DlBlendMode::V);
4462#undef TEST_MODE
4463}
4464
4465TEST_F(DisplayListRendering, BlendColorFilterOpacityCommuteCheck) {
4467 std::stringstream desc_str;
4469 desc_str << "blend[" << mode_string << ", " << color << "]";
4470 std::string desc = desc_str.str();
4471 DlBlendColorFilter filter(color, mode);
4472 if (filter.can_commute_with_opacity()) {
4473
4474
4475 } else {
4476 ASSERT_NE(DlColorFilter::MakeBlend(color, mode), nullptr) << desc;
4477 }
4478
4482
4483 DisplayListBuilder builder1;
4484 builder1.SaveLayer(kTestBounds2, &opacity_save_paint);
4485 builder1.SaveLayer(kTestBounds2, &filter_save_paint);
4486
4487 builder1.DrawRect(kRenderBounds, paint);
4488 builder1.Restore();
4489 builder1.Restore();
4490 auto display_list1 = builder1.Build();
4491
4492 DisplayListBuilder builder2;
4493 builder2.SaveLayer(kTestBounds2, &filter_save_paint);
4494 builder2.SaveLayer(kTestBounds2, &opacity_save_paint);
4495
4496 builder2.DrawRect(kRenderBounds, paint);
4497 builder2.Restore();
4498 builder2.Restore();
4499 auto display_list2 = builder2.Build();
4500
4501 for (auto& back_end : CanvasCompareTester::TestBackends) {
4502 auto provider = CanvasCompareTester::GetProvider(back_end);
4503 auto env = std::make_unique<RenderEnvironment>(
4504 provider.get(), PixelFormat::kN32PremulPixelFormat);
4505 auto results1 = env->getResult(display_list1);
4506 auto results2 = env->getResult(display_list2);
4507 if (filter.can_commute_with_opacity()) {
4508 CanvasCompareTester::compareToReference(
4509 results2.get(), results1.get(), desc, nullptr, nullptr,
4510 DlColor::kTransparent(), true, kTestWidth, kTestHeight, true);
4511 } else {
4512 CanvasCompareTester::quickCompareToReference(
4513 results1.get(), results2.get(), false, desc);
4514 }
4515 }
4516 };
4517
4519 test_mode_color(mode, DlColor::kTransparent());
4520 test_mode_color(mode, DlColor::kWhite());
4521 test_mode_color(mode, DlColor::kWhite().modulateOpacity(0.5));
4522 test_mode_color(mode, DlColor::kBlack());
4523 test_mode_color(mode, DlColor::kBlack().modulateOpacity(0.5));
4524 };
4525
4526#define TEST_MODE(V) test_mode(DlBlendMode::V);
4528#undef TEST_MODE
4529}
4530
4532
4533
4534 protected:
4536 test_src_colors = {
4537 DlColor::kBlack().withAlpha(0),
4538 DlColor::kBlack().withAlpha(0x7f),
4539 DlColor::kWhite().withAlpha(0x7f),
4540 DlColor::kBlack(),
4541 DlColor::kWhite(),
4542 DlColor::kRed(),
4543 DlColor::kGreen(),
4544 DlColor::kBlue(),
4545 DlColor::kDarkGrey(),
4546 DlColor::kLightGrey(),
4547 };
4548
4549
4550
4551 test_dst_colors.push_back(DlColor::kTransparent());
4552 const int step = 0x55;
4553 static_assert(step * 3 == 255);
4554 for (int a = step; a < 256; a += step) {
4555 for (int r = step; r < 256; r += step) {
4556 for (int g = step; g < 256; g += step) {
4557 for (
int b = step;
b < 256;
b += step) {
4558 test_dst_colors.push_back(
DlColor(a << 24 | r << 16 | g << 8 | b));
4559 }
4560 }
4561 }
4562 }
4563
4564 static constexpr float color_filter_matrix_nomtb[] = {
4565 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4566 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4567 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4568 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4569 };
4570 static constexpr float color_filter_matrix_mtb[] = {
4571 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4572 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4573 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4574 0.0001, 0.0001, 0.0001, 0.9997, 0.1,
4575 };
4576 color_filter_nomtb = DlColorFilter::MakeMatrix(color_filter_matrix_nomtb);
4577 color_filter_mtb = DlColorFilter::MakeMatrix(color_filter_matrix_mtb);
4578 EXPECT_FALSE(color_filter_nomtb->modifies_transparent_black());
4579 EXPECT_TRUE(color_filter_mtb->modifies_transparent_black());
4580
4581 test_data =
4582 get_output(test_dst_colors.size(), 1, true, [this](SkCanvas* canvas) {
4583 int x = 0;
4584 for (DlColor color : test_dst_colors) {
4585 SkPaint paint;
4586 paint.setColor(ToSkColor4f(color));
4587 paint.setBlendMode(SkBlendMode::kSrc);
4588 canvas->drawRect(SkRect::MakeXYWH(x, 0, 1, 1), paint);
4589 x++;
4590 }
4591 });
4592
4593
4594
4595
4596
4597 int data_count = test_data->image()->width();
4598 test_image_dst_data = get_output(
4599 data_count, data_count, true, [this, data_count](SkCanvas* canvas) {
4600 ASSERT_EQ(test_data->width(), data_count);
4601 ASSERT_EQ(test_data->height(), 1);
4602 for (
int y = 0;
y < data_count;
y++) {
4603 canvas->drawImage(test_data->image().get(), 0,
y);
4604 }
4605 });
4606 test_image_src_data = get_output(
4607 data_count, data_count, true, [this, data_count](SkCanvas* canvas) {
4608 ASSERT_EQ(test_data->width(), data_count);
4609 ASSERT_EQ(test_data->height(), 1);
4610 canvas->translate(data_count, 0);
4611 canvas->rotate(90);
4612 for (
int y = 0;
y < data_count;
y++) {
4613 canvas->drawImage(test_data->image().get(), 0,
y);
4614 }
4615 });
4616
4617 for (
int y = 0;
y < data_count;
y++) {
4618 for (
int x = 0;
x < data_count;
x++) {
4619 EXPECT_EQ(*test_image_dst_data->addr32(
x,
y), *test_data->addr32(
x, 0));
4620 EXPECT_EQ(*test_image_src_data->addr32(
x,
y), *test_data->addr32(
y, 0));
4621 }
4622 }
4623 }
4624
4625
4626
4627 static constexpr int kWasNotNop = 0x1;
4628 static constexpr int kWasMTB = 0x2;
4629
4630 std::vector<DlColor> test_src_colors;
4631 std::vector<DlColor> test_dst_colors;
4632
4633 std::shared_ptr<const DlColorFilter> color_filter_nomtb;
4634 std::shared_ptr<const DlColorFilter> color_filter_mtb;
4635
4636
4637 std::unique_ptr<RenderResult> test_data;
4638
4639
4640 std::unique_ptr<RenderResult> test_image_dst_data;
4641
4642
4643 std::unique_ptr<RenderResult> test_image_src_data;
4644
4645 std::unique_ptr<RenderResult> get_output(
4646 int w,
4647 int h,
4648 bool snapshot,
4649 const std::function<void(SkCanvas*)>& renderer) {
4650 auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(w, h));
4651 SkCanvas* canvas =
surface->getCanvas();
4652 renderer(canvas);
4653 return std::make_unique<SkRenderResult>(surface, snapshot);
4654 }
4655
4656 int check_color_result(DlColor dst_color,
4657 DlColor result_color,
4658 const sk_sp<DisplayList>& dl,
4659 const std::string& desc) {
4660 int ret = 0;
4661 bool is_error = false;
4662 if (dst_color.isTransparent() && !result_color.isTransparent()) {
4663 ret |= kWasMTB;
4664 is_error = !dl->modifies_transparent_black();
4665 }
4666 if (result_color != dst_color) {
4667 ret |= kWasNotNop;
4668 is_error = (dl->op_count() == 0u);
4669 }
4670 if (is_error) {
4671 FML_LOG(ERROR) << std::hex << dst_color <<
" filters to " << result_color
4672 << desc;
4673 }
4674 return ret;
4675 }
4676
4677 int check_image_result(const std::unique_ptr<RenderResult>& dst_data,
4678 const std::unique_ptr<RenderResult>& result_data,
4679 const sk_sp<DisplayList>& dl,
4680 const std::string& desc) {
4681 EXPECT_EQ(dst_data->width(), result_data->width());
4682 EXPECT_EQ(dst_data->height(), result_data->height());
4683 int all_flags = 0;
4684 for (
int y = 0;
y < dst_data->height();
y++) {
4685 const uint32_t* dst_pixels = dst_data->addr32(0,
y);
4686 const uint32_t* result_pixels = result_data->addr32(0,
y);
4687 for (
int x = 0;
x < dst_data->width();
x++) {
4688 all_flags |= check_color_result(
DlColor(dst_pixels[
x]),
4689 DlColor(result_pixels[
x]), dl, desc);
4690 }
4691 }
4692 return all_flags;
4693 }
4694
4695 void report_results(int all_flags,
4696 const sk_sp<DisplayList>& dl,
4697 const std::string& desc) {
4698 if (!dl->modifies_transparent_black()) {
4699 EXPECT_TRUE((all_flags & kWasMTB) == 0);
4700 } else if ((all_flags & kWasMTB) == 0) {
4701 FML_LOG(INFO) <<
"combination does not affect transparency: " << desc;
4702 }
4703 if (dl->op_count() == 0u) {
4704 EXPECT_TRUE((all_flags & kWasNotNop) == 0);
4705 } else if ((all_flags & kWasNotNop) == 0) {
4706 FML_LOG(INFO) <<
"combination could be classified as a nop: " << desc;
4707 }
4708 };
4709
4710 void test_mode_color_via_filter(DlBlendMode mode, DlColor color) {
4711 std::stringstream desc_stream;
4712 desc_stream << " using SkColorFilter::filterColor() with: ";
4714 desc_stream << "/" << color;
4715 std::string desc = desc_stream.str();
4716 DisplayListBuilder builder(DlRect::MakeWH(100.0f, 100.0f));
4718 builder.DrawRect(DlRect::MakeLTRB(0.0f, 0.0f, 10.0f, 10.0f), paint);
4719 auto dl = builder.Build();
4720 if (dl->modifies_transparent_black()) {
4721 ASSERT_TRUE(dl->op_count() != 0u);
4722 }
4723
4724 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4725 auto sk_color_filter =
4726 SkColorFilters::Blend(
ToSkColor4f(color),
nullptr, sk_mode);
4727 auto srgb = SkColorSpace::MakeSRGB();
4728 int all_flags = 0;
4729 if (sk_color_filter) {
4730 for (DlColor dst_color : test_dst_colors) {
4733 sk_color_filter->filterColor4f(dst_color_f, srgb.get(), srgb.get())
4734 .toSkColor());
4735 all_flags |= check_color_result(dst_color, result, dl, desc);
4736 }
4737 if ((all_flags & kWasMTB) != 0) {
4738 EXPECT_FALSE(sk_color_filter->isAlphaUnchanged());
4739 }
4740 }
4741 report_results(all_flags, dl, desc);
4742 };
4743
4744 void test_mode_color_via_rendering(DlBlendMode mode, DlColor color) {
4745 std::stringstream desc_stream;
4746 desc_stream << " rendering with: ";
4748 desc_stream << "/" << color;
4749 std::string desc = desc_stream.str();
4750 auto test_image = test_data->image();
4752 DlRect::MakeWH(test_image->width(), test_image->height());
4753 DisplayListBuilder builder(test_bounds);
4755 builder.DrawRect(test_bounds, dl_paint);
4756 auto dl = builder.Build();
4757 bool dl_is_elided = dl->op_count() == 0u;
4758 bool dl_affects_transparent_pixels = dl->modifies_transparent_black();
4759 ASSERT_TRUE(!dl_is_elided || !dl_affects_transparent_pixels);
4760
4761 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4762 SkPaint sk_paint;
4763 sk_paint.setBlendMode(sk_mode);
4765 for (auto& back_end : CanvasCompareTester::TestBackends) {
4766 auto provider = CanvasCompareTester::GetProvider(back_end);
4767 auto result_surface = provider->MakeOffscreenSurface(
4768 test_image->width(), test_image->height(),
4769 DlSurfaceProvider::kN32PremulPixelFormat);
4770 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4771 result_canvas->clear(SK_ColorTRANSPARENT);
4772 result_canvas->drawImage(test_image.get(), 0, 0);
4773 result_canvas->drawRect(
ToSkRect(test_bounds), sk_paint);
4774 if (GrDirectContext* direct_context = GrAsDirectContext(
4775 result_surface->sk_surface()->recordingContext())) {
4776 direct_context->flushAndSubmit();
4777 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4778 GrSyncCpu::kYes);
4779 }
4780 const std::unique_ptr<RenderResult> result_pixels =
4781 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4782
4783 int all_flags = check_image_result(test_data, result_pixels, dl, desc);
4784 report_results(all_flags, dl, desc);
4785 }
4786 };
4787
4788 void test_attributes_image(DlBlendMode mode,
4789 DlColor color,
4790 const DlColorFilter* color_filter,
4791 DlImageFilter* image_filter) {
4792
4793 std::stringstream desc_stream;
4794 desc_stream << " rendering with: ";
4796 desc_stream << "/" << color;
4797 std::string cf_mtb = color_filter
4798 ? color_filter->modifies_transparent_black()
4799 ? "modifies transparency"
4800 : "preserves transparency"
4801 : "no filter";
4802 desc_stream << ", CF: " << cf_mtb;
4803 std::string if_mtb = image_filter
4804 ? image_filter->modifies_transparent_black()
4805 ? "modifies transparency"
4806 : "preserves transparency"
4807 : "no filter";
4808 desc_stream << ", IF: " << if_mtb;
4809 std::string desc = desc_stream.str();
4810
4811 DisplayListBuilder builder(DlRect::MakeWH(100.0f, 100.0f));
4816 builder.DrawImage(DlImage::Make(test_image_src_data->image()),
4817 DlPoint(0, 0), DlImageSampling::kNearestNeighbor, &paint);
4818 auto dl = builder.Build();
4819
4820 int w = test_image_src_data->width();
4821 int h = test_image_src_data->height();
4822 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4823 SkPaint sk_paint;
4824 sk_paint.setBlendMode(sk_mode);
4826 sk_paint.setColorFilter(
ToSk(color_filter));
4827 sk_paint.setImageFilter(
ToSk(image_filter));
4828 for (auto& back_end : CanvasCompareTester::TestBackends) {
4829 auto provider = CanvasCompareTester::GetProvider(back_end);
4830 auto result_surface = provider->MakeOffscreenSurface(
4831 w, h, DlSurfaceProvider::kN32PremulPixelFormat);
4832 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4833 result_canvas->clear(SK_ColorTRANSPARENT);
4834 result_canvas->drawImage(test_image_dst_data->image(), 0, 0);
4835 result_canvas->drawImage(test_image_src_data->image(), 0, 0,
4836 SkSamplingOptions(), &sk_paint);
4837 if (GrDirectContext* direct_context = GrAsDirectContext(
4838 result_surface->sk_surface()->recordingContext())) {
4839 direct_context->flushAndSubmit();
4840 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4841 GrSyncCpu::kYes);
4842 }
4843 std::unique_ptr<RenderResult> result_pixels =
4844 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4845
4846 int all_flags =
4847 check_image_result(test_image_dst_data, result_pixels, dl, desc);
4848 report_results(all_flags, dl, desc);
4849 }
4850 };
4851};
4852
4853TEST_F(DisplayListNopTest, BlendModeAndColorViaColorFilter) {
4855 for (DlColor color : test_src_colors) {
4856 test_mode_color_via_filter(mode, color);
4857 }
4858 };
4859
4860#define TEST_MODE(V) test_mode_filter(DlBlendMode::V);
4862#undef TEST_MODE
4863}
4864
4865TEST_F(DisplayListNopTest, BlendModeAndColorByRendering) {
4867
4868 for (DlColor color : test_src_colors) {
4869 test_mode_color_via_rendering(mode, color);
4870 }
4871 };
4872
4873#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4875#undef TEST_MODE
4876}
4877
4878TEST_F(DisplayListNopTest, BlendModeAndColorAndFiltersByRendering) {
4880 auto image_filter_nomtb = DlColorFilterImageFilter(color_filter_nomtb);
4881 auto image_filter_mtb = DlColorFilterImageFilter(color_filter_mtb);
4882 for (DlColor color : test_src_colors) {
4883 test_attributes_image(mode, color, nullptr, nullptr);
4884 test_attributes_image(mode, color, color_filter_nomtb.get(), nullptr);
4885 test_attributes_image(mode, color, color_filter_mtb.get(), nullptr);
4886 test_attributes_image(mode, color, nullptr, &image_filter_nomtb);
4887 test_attributes_image(mode, color, nullptr, &image_filter_mtb);
4888 }
4889 };
4890
4891#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4893#undef TEST_MODE
4894}
4895
4896#undef FOR_EACH_BLEND_MODE_ENUM
4897
4898}
4899}
TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowFirst)
DlPaint & setBlendMode(DlBlendMode mode)
DlPaint & setImageFilter(std::nullptr_t filter)
DlPaint & setOpacity(DlScalar opacity)
DlPaint & setColorFilter(std::nullptr_t filter)
#define FOR_EACH_BLEND_MODE_ENUM(FUNC)
#define FML_LOG(severity)
DisplayListRenderingTestBase<::testing::Test > DisplayListRendering
const DlPoint kTestCenter2
SkPaint ToSk(const DlPaint &paint)
SkColor4f ToSkColor4f(DlColor color)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
impeller::BlendMode DlBlendMode
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder h
const SkRect & ToSkRect(const DlRect &rect)
const char * BlendModeToString(BlendMode blend_mode)