3606 {
3608 std::stringstream desc_str;
3610 desc_str << "blend[" << mode_string << ", " << color << "]";
3611 std::string desc = desc_str.str();
3612 DlBlendColorFilter filter(color, mode);
3613 if (filter.modifies_transparent_black()) {
3614 ASSERT_NE(DlColorFilter::MakeBlend(color, mode), nullptr) << desc;
3615 }
3616
3619
3620 DisplayListBuilder builder1;
3622 builder1.Rotate(45);
3624 builder1.DrawRect(kRenderBounds, paint);
3625 sk_sp<DisplayList> display_list1 = builder1.Build();
3626
3627 DisplayListBuilder builder2;
3629 builder2.Rotate(45);
3631 builder2.SaveLayer(kTestBounds2, &filter_save_paint);
3632 builder2.DrawRect(kRenderBounds, paint);
3633 builder2.Restore();
3634 sk_sp<DisplayList> display_list2 = builder2.Build();
3635
3636 for (BackendType back_end : GetTestBackends()) {
3637 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
3638 std::unique_ptr<RenderEnvironment> env =
3639 std::make_unique<RenderEnvironment>(provider.get(),
3640 PixelFormat::kN32Premul);
3641 RenderResult results1 = env->GetResult(display_list1);
3642 RenderResult results2 = env->GetResult(display_list2);
3643 int modified_transparent_pixels =
3644 CanvasCompareTester::countModifiedTransparentPixels(results1,
3645 results2);
3646 EXPECT_EQ(filter.modifies_transparent_black(),
3647 modified_transparent_pixels != 0)
3648 << provider->GetBackendName() << ": " << desc;
3649 }
3650 };
3651
3653 test_mode_color(mode, DlColor::kTransparent());
3654 test_mode_color(mode, DlColor::kWhite());
3655 test_mode_color(mode, DlColor::kWhite().modulateOpacity(0.5));
3656 test_mode_color(mode, DlColor::kBlack());
3657 test_mode_color(mode, DlColor::kBlack().modulateOpacity(0.5));
3658 };
3659
3660#define TEST_MODE(V) test_mode(DlBlendMode::V);
3662#undef TEST_MODE
3663}
3664
3665TEST_F(DisplayListRendering, BlendColorFilterOpacityCommuteCheck) {
3667 std::stringstream desc_str;
3669 desc_str << "blend[" << mode_string << ", " << color << "]";
3670 std::string desc = desc_str.str();
3671 DlBlendColorFilter filter(color, mode);
3672 if (filter.can_commute_with_opacity()) {
3673
3674
3675 } else {
3676 ASSERT_NE(DlColorFilter::MakeBlend(color, mode), nullptr) << desc;
3677 }
3678
3682
3683 DisplayListBuilder builder1;
3684 builder1.SaveLayer(kTestBounds2, &opacity_save_paint);
3685 builder1.SaveLayer(kTestBounds2, &filter_save_paint);
3686
3687 builder1.DrawRect(kRenderBounds, paint);
3688 builder1.Restore();
3689 builder1.Restore();
3690 sk_sp<DisplayList> display_list1 = builder1.Build();
3691
3692 DisplayListBuilder builder2;
3693 builder2.SaveLayer(kTestBounds2, &filter_save_paint);
3694 builder2.SaveLayer(kTestBounds2, &opacity_save_paint);
3695
3696 builder2.DrawRect(kRenderBounds, paint);
3697 builder2.Restore();
3698 builder2.Restore();
3699 sk_sp<DisplayList> display_list2 = builder2.Build();
3700
3701 for (BackendType back_end : GetTestBackends()) {
3702 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
3703 std::string provider_desc = " " + provider->GetBackendName() + " " + desc;
3704 std::unique_ptr<RenderEnvironment> env =
3705 std::make_unique<RenderEnvironment>(provider.get(),
3706 PixelFormat::kN32Premul);
3707
3708 RenderResult results1 = env->GetResult(display_list1);
3709 RenderResult results2 = env->GetResult(display_list2);
3710 if (filter.can_commute_with_opacity()) {
3711 CanvasCompareTester::compareToReference(
3712 results2, results1, provider_desc, nullptr, nullptr,
3713 DlColor::kTransparent(), true, kTestWidth, kTestHeight, true);
3714 } else {
3715 CanvasCompareTester::quickCompareToReference(results1, results2, false,
3716 provider_desc);
3717 }
3718 }
3719 };
3720
3722 test_mode_color(mode, DlColor::kTransparent());
3723 test_mode_color(mode, DlColor::kWhite());
3724 test_mode_color(mode, DlColor::kWhite().modulateOpacity(0.5));
3725 test_mode_color(mode, DlColor::kBlack());
3726 test_mode_color(mode, DlColor::kBlack().modulateOpacity(0.5));
3727 };
3728
3729#define TEST_MODE(V) test_mode(DlBlendMode::V);
3731#undef TEST_MODE
3732}
3733
3734class DisplayListNopTest : public DisplayListRendering {
3735
3736
3737 protected:
3738 DisplayListNopTest() : DisplayListRendering() {
3739 test_src_colors = {
3740 DlColor::kBlack().withAlpha(0),
3741 DlColor::kBlack().withAlpha(0x7f),
3742 DlColor::kWhite().withAlpha(0x7f),
3743 DlColor::kBlack(),
3744 DlColor::kWhite(),
3745 DlColor::kRed(),
3746 DlColor::kGreen(),
3747 DlColor::kBlue(),
3748 DlColor::kDarkGrey(),
3749 DlColor::kLightGrey(),
3750 };
3751
3752
3753
3754 test_dst_colors.push_back(DlColor::kTransparent());
3755 const int step = 0x55;
3756 static_assert(step * 3 == 255);
3757 for (int a = step; a < 256; a += step) {
3758 for (int r = step; r < 256; r += step) {
3759 for (int g = step; g < 256; g += step) {
3760 for (
int b = step;
b < 256;
b += step) {
3761 test_dst_colors.push_back(
DlColor(a << 24 | r << 16 | g << 8 | b));
3762 }
3763 }
3764 }
3765 }
3766
3767 static constexpr float color_filter_matrix_nomtb[] = {
3768 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3769 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3770 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3771 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3772 };
3773 static constexpr float color_filter_matrix_mtb[] = {
3774 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3775 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3776 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
3777 0.0001, 0.0001, 0.0001, 0.9997, 0.1,
3778 };
3779 color_filter_nomtb = DlColorFilter::MakeMatrix(color_filter_matrix_nomtb);
3780 color_filter_mtb = DlColorFilter::MakeMatrix(color_filter_matrix_mtb);
3781 EXPECT_FALSE(color_filter_nomtb->modifies_transparent_black());
3782 EXPECT_TRUE(color_filter_mtb->modifies_transparent_black());
3783 }
3784
3785 struct TestData {
3786
3787
3788 sk_sp<DlImage> test_image_1d;
3789 RenderResult test_pixels;
3790
3791
3792
3793 sk_sp<DlImage> dst_image_2d;
3794 RenderResult dst_pixels;
3795
3796
3797
3798 sk_sp<DlImage> src_image_2d;
3799 RenderResult src_pixels;
3800 };
3801
3802 const TestData make_test_data(DlSurfaceProvider* provider) {
3803 std::shared_ptr<DlSurfaceInstance> test_surface = get_output(
3804 provider, test_dst_colors.size(), 1, true, [this](DlCanvas* canvas) {
3805 int x = 0;
3806 DlPaint paint;
3807 paint.setBlendMode(DlBlendMode::kSrc);
3808 for (DlColor color : test_dst_colors) {
3809 paint.setColor(color);
3810 canvas->DrawRect(DlRect::MakeXYWH(x, 0, 1, 1), paint);
3811 x++;
3812 }
3813 });
3814 sk_sp<DlImage> test_image = test_surface->SnapshotToImage();
3815 std::shared_ptr<DlPixelData> test_pixels =
3816 test_surface->SnapshotToPixelData();
3817
3818
3819
3820
3821
3822 int data_count = test_image->width();
3823 std::shared_ptr<DlSurfaceInstance> dst_surface =
3824 get_output(provider, data_count, data_count, true,
3825 [&test_image, data_count](DlCanvas* canvas) {
3826 ASSERT_EQ(test_image->width(), data_count);
3827 ASSERT_EQ(test_image->height(), 1);
3828 for (
int y = 0;
y < data_count;
y++) {
3829 canvas->DrawImage(test_image,
DlPoint(0,
y),
3830 DlImageSampling::kNearestNeighbor);
3831 }
3832 });
3833 std::shared_ptr<DlPixelData> dst_pixels =
3834 dst_surface->SnapshotToPixelData();
3835
3836 std::shared_ptr<DlSurfaceInstance> src_surface =
3837 get_output(provider, data_count, data_count, true,
3838 [&test_image, data_count](DlCanvas* canvas) {
3839 ASSERT_EQ(test_image->width(), data_count);
3840 ASSERT_EQ(test_image->height(), 1);
3841 canvas->Translate(data_count, 0);
3842 canvas->Rotate(90);
3843 for (
int y = 0;
y < data_count;
y++) {
3844 canvas->DrawImage(test_image,
DlPoint(0,
y),
3845 DlImageSampling::kNearestNeighbor);
3846 }
3847 });
3848 std::shared_ptr<DlPixelData> src_pixels =
3849 src_surface->SnapshotToPixelData();
3850
3851
3852 for (
int y = 0;
y < data_count;
y++) {
3853 for (
int x = 0;
x < data_count;
x++) {
3854 EXPECT_EQ(*dst_pixels->addr32(
x,
y), *test_pixels->addr32(
x, 0));
3855 EXPECT_EQ(*src_pixels->addr32(
x,
y), *test_pixels->addr32(
y, 0));
3856 }
3857 }
3858
3859 return {
3860 .test_image_1d = test_surface->SnapshotToImage(),
3861 .test_pixels = RenderResult::Make(test_pixels),
3862
3863 .dst_image_2d = dst_surface->SnapshotToImage(),
3864 .dst_pixels = RenderResult::Make(dst_pixels),
3865
3866 .src_image_2d = src_surface->SnapshotToImage(),
3867 .src_pixels = RenderResult::Make(src_pixels),
3868 };
3869 }
3870
3871
3872
3873 static constexpr int kWasNotNop = 0x1;
3874 static constexpr int kWasMTB = 0x2;
3875
3876 std::vector<DlColor> test_src_colors;
3877 std::vector<DlColor> test_dst_colors;
3878
3879 std::shared_ptr<const DlColorFilter> color_filter_nomtb;
3880 std::shared_ptr<const DlColorFilter> color_filter_mtb;
3881
3882 std::map<DlSurfaceProvider::BackendType, TestData> test_datas;
3883
3884 const TestData GetTestData(DlSurfaceProvider* provider) {
3885 auto entry = test_datas.find(provider->GetBackendType());
3886 if (entry == test_datas.end()) {
3887 TestData test_data = make_test_data(provider);
3888 test_datas[provider->GetBackendType()] = test_data;
3889 return test_data;
3890 }
3891 return entry->second;
3892 }
3893
3894 std::shared_ptr<DlSurfaceInstance> get_output(
3895 DlSurfaceProvider* provider,
3896 int w,
3897 int h,
3898 bool snapshot,
3899 const std::function<void(DlCanvas*)>& renderer) {
3900 std::shared_ptr<DlSurfaceInstance>
surface =
3901 provider->MakeOffscreenSurface(w, h, DlSurfaceProvider::kN32Premul);
3902 DisplayListBuilder builder;
3903 renderer(&builder);
3904 surface->RenderDisplayList(builder.Build());
3905 surface->FlushSubmitCpuSync();
3907 }
3908
3909 int check_color_result(DlColor dst_color,
3910 DlColor result_color,
3913 const sk_sp<DisplayList>& dl,
3914 const std::string& desc) {
3915 int ret = 0;
3916 bool is_error = false;
3917 if (dst_color.isTransparent() && !result_color.isTransparent()) {
3918 ret |= kWasMTB;
3919 is_error = !dl->modifies_transparent_black();
3920 }
3921 if (result_color != dst_color) {
3922 ret |= kWasNotNop;
3923 is_error = (dl->op_count() == 0u);
3924 }
3925 if (is_error) {
3926 FML_LOG(ERROR) << std::hex << dst_color
3927 << std::dec <<
" at " <<
x <<
", " <<
y
3928 << " filters to " << std::hex << result_color
3929 << desc;
3930 }
3931 return ret;
3932 }
3933
3934 int check_image_result(const RenderResult& dst_data,
3935 const RenderResult& result_data,
3936 const sk_sp<DisplayList>& dl,
3937 const std::string& desc) {
3938 EXPECT_EQ(dst_data.pixel_data->width(), result_data.pixel_data->width());
3939 EXPECT_EQ(dst_data.pixel_data->height(), result_data.pixel_data->height());
3940 int all_flags = 0;
3941 for (uint32_t
y = 0;
y < dst_data.pixel_data->height();
y++) {
3942 const uint32_t* dst_pixels = dst_data.pixel_data->addr32(0,
y);
3943 const uint32_t* result_pixels = result_data.pixel_data->addr32(0,
y);
3944 for (uint32_t
x = 0;
x < dst_data.pixel_data->width();
x++) {
3945 all_flags |= check_color_result(
3947 }
3948 }
3949 return all_flags;
3950 }
3951
3952 void report_results(int all_flags,
3953 const sk_sp<DisplayList>& dl,
3954 const std::string& desc) {
3955 if (!dl->modifies_transparent_black()) {
3956 EXPECT_TRUE((all_flags & kWasMTB) == 0);
3957 } else if ((all_flags & kWasMTB) == 0) {
3958 FML_LOG(INFO) <<
"combination does not affect transparency: " << desc;
3959 }
3960 if (dl->op_count() == 0u) {
3961 EXPECT_TRUE((all_flags & kWasNotNop) == 0);
3962 } else if ((all_flags & kWasNotNop) == 0) {
3963 FML_LOG(INFO) <<
"combination could be classified as a nop: " << desc;
3964 }
3965 };
3966
3967 void test_mode_color_via_filter(DlBlendMode mode, DlColor color) {
3968 std::stringstream desc_stream;
3969 desc_stream << " using SkColorFilter::filterColor() with: ";
3971 desc_stream << "/" << color;
3972 std::string desc = desc_stream.str();
3973 DisplayListBuilder builder(DlRect::MakeWH(100.0f, 100.0f));
3975 builder.DrawRect(DlRect::MakeLTRB(0.0f, 0.0f, 10.0f, 10.0f), paint);
3976 sk_sp<DisplayList> dl = builder.Build();
3977 if (dl->modifies_transparent_black()) {
3978 ASSERT_TRUE(dl->op_count() != 0u);
3979 }
3980
3981 SkBlendMode sk_mode =
static_cast<SkBlendMode
>(
mode);
3982 sk_sp<SkColorFilter> sk_color_filter =
3983 SkColorFilters::Blend(
ToSkColor4f(color),
nullptr, sk_mode);
3984 sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
3985 int all_flags = 0;
3986 if (sk_color_filter) {
3987 for (DlColor dst_color : test_dst_colors) {
3990 sk_color_filter->filterColor4f(dst_color_f, srgb.get(), srgb.get())
3991 .toSkColor());
3992 all_flags |=
3993 check_color_result(dst_color, result, 0, 0, dl, desc);
3994 }
3995 if ((all_flags & kWasMTB) != 0) {
3996 EXPECT_FALSE(sk_color_filter->isAlphaUnchanged());
3997 }
3998 }
3999 report_results(all_flags, dl, desc);
4000 };
4001
4002 void test_mode_color_via_rendering(DlBlendMode mode, DlColor color) {
4003 std::stringstream desc_stream;
4004 desc_stream << " rendering with: ";
4006 desc_stream << "/" << color;
4007 std::string desc = desc_stream.str();
4008 DisplayListBuilder builder_for_properties;
4010 builder_for_properties.DrawRect(DlRect::MakeWH(100, 100), dl_paint);
4011 sk_sp<DisplayList> properties_display_list = builder_for_properties.Build();
4012 bool dl_is_elided = properties_display_list->op_count() == 0u;
4013 bool dl_affects_transparent_pixels =
4014 properties_display_list->modifies_transparent_black();
4015 ASSERT_TRUE(!dl_is_elided || !dl_affects_transparent_pixels);
4016
4020 for (BackendType back_end : GetTestBackends()) {
4021 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
4022 const TestData test_data = GetTestData(provider.get());
4023 std::string provider_desc = " " + provider->GetBackendName() + desc;
4024
4025 sk_sp<DlImage> test_image = test_data.test_image_1d;
4027 DlRect::MakeWH(test_image->width(), test_image->height());
4028 std::shared_ptr<DlSurfaceInstance> result_surface =
4029 provider->MakeOffscreenSurface(test_image->width(),
4030 test_image->height(),
4031 DlSurfaceProvider::kN32Premul);
4032 DisplayListBuilder builder_for_rendering;
4033 builder_for_rendering.Clear(DlColor::kTransparent());
4034 builder_for_rendering.DrawImage(test_image,
DlPoint(0, 0),
4035 DlImageSampling::kNearestNeighbor);
4036 builder_for_rendering.DrawRect(test_bounds, paint);
4037 result_surface->RenderDisplayList(builder_for_rendering.Build());
4038 result_surface->FlushSubmitCpuSync();
4039 RenderResult result_pixels = RenderResult::Make(result_surface);
4040
4041 int all_flags =
4042 check_image_result(test_data.test_pixels, result_pixels,
4043 properties_display_list, provider_desc);
4044 report_results(all_flags, properties_display_list, provider_desc);
4045 }
4046 };
4047
4048 void test_attributes_image(DlBlendMode mode,
4049 DlColor color,
4050 const DlColorFilter* color_filter,
4051 DlImageFilter* image_filter) {
4052
4053 std::stringstream desc_stream;
4054 desc_stream << " rendering with: ";
4056 desc_stream << "/" << color;
4057 std::string cf_mtb = color_filter
4058 ? color_filter->modifies_transparent_black()
4059 ? "modifies transparency"
4060 : "preserves transparency"
4061 : "no filter";
4062 desc_stream << ", CF: " << cf_mtb;
4063 std::string if_mtb = image_filter
4064 ? image_filter->modifies_transparent_black()
4065 ? "modifies transparency"
4066 : "preserves transparency"
4067 : "no filter";
4068 desc_stream << ", IF: " << if_mtb;
4069 std::string desc = desc_stream.str();
4070
4071 for (BackendType back_end : GetTestBackends()) {
4072 std::unique_ptr<DlSurfaceProvider> provider = GetProvider(back_end);
4073 const TestData test_data = GetTestData(provider.get());
4074 std::string provider_desc = " " + provider->GetBackendName() + desc;
4075
4076 DisplayListBuilder builder_for_properties(DlRect::MakeWH(100.0f, 100.0f));
4081 builder_for_properties.DrawImage(test_data.src_image_2d,
DlPoint(0, 0),
4082 DlImageSampling::kNearestNeighbor,
4083 &paint);
4084 sk_sp<DisplayList> properties_display_list =
4085 builder_for_properties.Build();
4086
4087 int w = test_data.src_image_2d->width();
4088 int h = test_data.src_image_2d->height();
4089 std::shared_ptr<DlSurfaceInstance> result_surface =
4090 provider->MakeOffscreenSurface(w, h, DlSurfaceProvider::kN32Premul);
4091 DisplayListBuilder builder_for_rendering;
4092 builder_for_rendering.Clear(DlColor::kTransparent());
4093 builder_for_rendering.DrawImage(test_data.dst_image_2d,
DlPoint(0, 0),
4094 DlImageSampling::kNearestNeighbor);
4095 builder_for_rendering.DrawImage(test_data.src_image_2d,
DlPoint(0, 0),
4096 DlImageSampling::kNearestNeighbor,
4097 &paint);
4098 result_surface->RenderDisplayList(builder_for_rendering.Build());
4099 result_surface->FlushSubmitCpuSync();
4100 RenderResult result_pixels = RenderResult::Make(result_surface);
4101
4102 int all_flags =
4103 check_image_result(test_data.dst_pixels, result_pixels,
4104 properties_display_list, provider_desc);
4105 report_results(all_flags, properties_display_list, provider_desc);
4106 }
4107 };
4108};
4109
4110TEST_F(DisplayListNopTest, BlendModeAndColorViaColorFilter) {
4112 for (DlColor color : test_src_colors) {
4113 test_mode_color_via_filter(mode, color);
4114 }
4115 };
4116
4117#define TEST_MODE(V) test_mode_filter(DlBlendMode::V);
4119#undef TEST_MODE
4120}
4121
4122TEST_F(DisplayListNopTest, BlendModeAndColorByRendering) {
4124
4125 for (DlColor color : test_src_colors) {
4126 test_mode_color_via_rendering(mode, color);
4127 }
4128 };
4129
4130#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4132#undef TEST_MODE
4133}
4134
4135TEST_F(DisplayListNopTest, BlendModeAndColorAndFiltersByRendering) {
4137 DlColorFilterImageFilter image_filter_nomtb(color_filter_nomtb);
4138 DlColorFilterImageFilter image_filter_mtb(color_filter_mtb);
4139 for (DlColor color : test_src_colors) {
4140 test_attributes_image(mode, color, nullptr, nullptr);
4141 test_attributes_image(mode, color, color_filter_nomtb.get(), nullptr);
4142 test_attributes_image(mode, color, color_filter_mtb.get(), nullptr);
4143 test_attributes_image(mode, color, nullptr, &image_filter_nomtb);
4144 test_attributes_image(mode, color, nullptr, &image_filter_mtb);
4145 }
4146 };
4147
4148#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4150#undef TEST_MODE
4151}
4152
4153#undef FOR_EACH_BLEND_MODE_ENUM
4154
4155}
4156}
TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowFirst)
DlPaint & setColor(DlColor color)
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)
const DlPoint kTestCenter2
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 char * BlendModeToString(BlendMode blend_mode)