@@ -448,7 +448,7 @@ TEST_P(AiksTest, CanRenderLinearGradientWithDitheringDisabled) {
448
448
449
449
TEST_P (AiksTest, CanRenderLinearGradientWithDitheringEnabled) {
450
450
CanRenderLinearGradientWithDithering (this , true );
451
- } // namespace
451
+ }
452
452
453
453
static void CanRenderRadialGradientWithDithering (AiksTest* aiks_test,
454
454
bool use_dithering) {
@@ -2416,19 +2416,18 @@ TEST_P(AiksTest, ClearColorOptimizationDoesNotApplyForBackdropFilters) {
2416
2416
Picture picture = canvas.EndRecordingAsPicture ();
2417
2417
2418
2418
std::optional<Color> actual_color;
2419
+ bool found_subpass = false ;
2419
2420
picture.pass ->IterateAllElements ([&](EntityPass::Element& element) -> bool {
2420
2421
if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
2421
2422
actual_color = subpass->get ()->GetClearColor ();
2423
+ found_subpass = true ;
2422
2424
}
2423
2425
// Fail if the first element isn't a subpass.
2424
2426
return true ;
2425
2427
});
2426
2428
2427
- ASSERT_TRUE (actual_color.has_value ());
2428
- if (!actual_color) {
2429
- return ;
2430
- }
2431
- ASSERT_EQ (actual_color.value (), Color::BlackTransparent ());
2429
+ EXPECT_TRUE (found_subpass);
2430
+ EXPECT_FALSE (actual_color.has_value ());
2432
2431
}
2433
2432
2434
2433
TEST_P (AiksTest, CollapsedDrawPaintInSubpass) {
@@ -3645,5 +3644,168 @@ TEST_P(AiksTest, MaskBlurWithZeroSigmaIsSkipped) {
3645
3644
ASSERT_TRUE (OpenPlaygroundHere (canvas.EndRecordingAsPicture ()));
3646
3645
}
3647
3646
3647
+ TEST_P (AiksTest, AdvancedBlendWithClearColorOptimization) {
3648
+ Canvas canvas;
3649
+ canvas.DrawPaint (
3650
+ {.color = {1.0 , 1.0 , 0.0 , 1.0 }, .blend_mode = BlendMode::kSource });
3651
+
3652
+ canvas.DrawRect (
3653
+ Rect::MakeXYWH (0 , 0 , 200 , 300 ),
3654
+ {.color = {1.0 , 0.0 , 1.0 , 1.0 }, .blend_mode = BlendMode::kMultiply });
3655
+ }
3656
+
3657
+ TEST_P (AiksTest, GaussianBlurAtPeripheryVertical) {
3658
+ Canvas canvas;
3659
+
3660
+ canvas.Scale (GetContentScale ());
3661
+ canvas.DrawRRect (Rect::MakeLTRB (0 , 0 , GetWindowSize ().width , 100 ),
3662
+ Size (10 , 10 ), Paint{.color = Color::LimeGreen ()});
3663
+ canvas.DrawRRect (Rect::MakeLTRB (0 , 110 , GetWindowSize ().width , 210 ),
3664
+ Size (10 , 10 ), Paint{.color = Color::Magenta ()});
3665
+ canvas.ClipRect (Rect::MakeLTRB (100 , 0 , 200 , GetWindowSize ().height ));
3666
+ canvas.SaveLayer ({.blend_mode = BlendMode::kSource }, std::nullopt,
3667
+ ImageFilter::MakeBlur (Sigma (20.0 ), Sigma (20.0 ),
3668
+ FilterContents::BlurStyle::kNormal ,
3669
+ Entity::TileMode::kClamp ));
3670
+ canvas.Restore ();
3671
+
3672
+ ASSERT_TRUE (OpenPlaygroundHere (canvas.EndRecordingAsPicture ()));
3673
+ }
3674
+
3675
+ TEST_P (AiksTest, GaussianBlurAtPeripheryHorizontal) {
3676
+ Canvas canvas;
3677
+
3678
+ canvas.Scale (GetContentScale ());
3679
+ std::shared_ptr<Texture> boston = CreateTextureForFixture (" boston.jpg" );
3680
+ canvas.DrawImageRect (
3681
+ std::make_shared<Image>(boston),
3682
+ Rect::MakeXYWH (0 , 0 , boston->GetSize ().width , boston->GetSize ().height ),
3683
+ Rect::MakeLTRB (0 , 0 , GetWindowSize ().width , 100 ), Paint{});
3684
+ canvas.DrawRRect (Rect::MakeLTRB (0 , 110 , GetWindowSize ().width , 210 ),
3685
+ Size (10 , 10 ), Paint{.color = Color::Magenta ()});
3686
+ canvas.ClipRect (Rect::MakeLTRB (0 , 50 , GetWindowSize ().width , 150 ));
3687
+ canvas.SaveLayer ({.blend_mode = BlendMode::kSource }, std::nullopt,
3688
+ ImageFilter::MakeBlur (Sigma (20.0 ), Sigma (20.0 ),
3689
+ FilterContents::BlurStyle::kNormal ,
3690
+ Entity::TileMode::kClamp ));
3691
+ canvas.Restore ();
3692
+ ASSERT_TRUE (OpenPlaygroundHere (canvas.EndRecordingAsPicture ()));
3693
+ }
3694
+
3695
+ #define FLT_FORWARD (mock, real, method ) \
3696
+ EXPECT_CALL (*mock, method()) \
3697
+ .WillRepeatedly(::testing::Return(real->method ()));
3698
+
3699
+ TEST_P (AiksTest, GaussianBlurWithoutDecalSupport) {
3700
+ if (GetParam () != PlaygroundBackend::kMetal ) {
3701
+ GTEST_SKIP_ (
3702
+ " This backend doesn't yet support setting device capabilities." );
3703
+ }
3704
+ if (!WillRenderSomething ()) {
3705
+ // Sometimes these tests are run without playgrounds enabled which is
3706
+ // pointless for this test since we are asserting that
3707
+ // `SupportsDecalSamplerAddressMode` is called.
3708
+ GTEST_SKIP_ (" This test requires playgrounds." );
3709
+ }
3710
+
3711
+ std::shared_ptr<const Capabilities> old_capabilities =
3712
+ GetContext ()->GetCapabilities ();
3713
+ auto mock_capabilities = std::make_shared<MockCapabilities>();
3714
+ EXPECT_CALL (*mock_capabilities, SupportsDecalSamplerAddressMode ())
3715
+ .Times (::testing::AtLeast (1 ))
3716
+ .WillRepeatedly (::testing::Return (false ));
3717
+ FLT_FORWARD (mock_capabilities, old_capabilities, GetDefaultColorFormat);
3718
+ FLT_FORWARD (mock_capabilities, old_capabilities, GetDefaultStencilFormat);
3719
+ FLT_FORWARD (mock_capabilities, old_capabilities, SupportsOffscreenMSAA);
3720
+ FLT_FORWARD (mock_capabilities, old_capabilities,
3721
+ SupportsImplicitResolvingMSAA);
3722
+ FLT_FORWARD (mock_capabilities, old_capabilities, SupportsReadFromResolve);
3723
+ FLT_FORWARD (mock_capabilities, old_capabilities, SupportsFramebufferFetch);
3724
+ FLT_FORWARD (mock_capabilities, old_capabilities, SupportsSSBO);
3725
+ FLT_FORWARD (mock_capabilities, old_capabilities, SupportsCompute);
3726
+ FLT_FORWARD (mock_capabilities, old_capabilities,
3727
+ SupportsTextureToTextureBlits);
3728
+ ASSERT_TRUE (SetCapabilities (mock_capabilities).ok ());
3729
+
3730
+ auto texture = std::make_shared<Image>(CreateTextureForFixture (" boston.jpg" ));
3731
+ Canvas canvas;
3732
+ canvas.Scale (GetContentScale () * 0.5 );
3733
+ canvas.DrawPaint ({.color = Color::Black ()});
3734
+ canvas.DrawImage (
3735
+ texture, Point (200 , 200 ),
3736
+ {
3737
+ .image_filter = ImageFilter::MakeBlur (
3738
+ Sigma (20.0 ), Sigma (20.0 ), FilterContents::BlurStyle::kNormal ,
3739
+ Entity::TileMode::kDecal ),
3740
+ });
3741
+ ASSERT_TRUE (OpenPlaygroundHere (canvas.EndRecordingAsPicture ()));
3742
+ }
3743
+
3744
+ TEST_P (AiksTest, GaussianBlurOneDimension) {
3745
+ Canvas canvas;
3746
+
3747
+ canvas.Scale (GetContentScale ());
3748
+ canvas.Scale ({0.5 , 0.5 , 1.0 });
3749
+ std::shared_ptr<Texture> boston = CreateTextureForFixture (" boston.jpg" );
3750
+ canvas.DrawImage (std::make_shared<Image>(boston), Point (100 , 100 ), Paint{});
3751
+ canvas.SaveLayer ({.blend_mode = BlendMode::kSource }, std::nullopt,
3752
+ ImageFilter::MakeBlur (Sigma (50.0 ), Sigma (0.0 ),
3753
+ FilterContents::BlurStyle::kNormal ,
3754
+ Entity::TileMode::kClamp ));
3755
+ canvas.Restore ();
3756
+ ASSERT_TRUE (OpenPlaygroundHere (canvas.EndRecordingAsPicture ()));
3757
+ }
3758
+
3759
+ // Smoketest to catch issues with the coverage hint.
3760
+ // Draws a rotated blurred image within a rectangle clip. The center of the clip
3761
+ // rectangle is the center of the rotated image. The entire area of the clip
3762
+ // rectangle should be filled with opaque colors output by the blur.
3763
+ TEST_P (AiksTest, GaussianBlurRotatedAndClipped) {
3764
+ Canvas canvas;
3765
+ std::shared_ptr<Texture> boston = CreateTextureForFixture (" boston.jpg" );
3766
+ Rect bounds =
3767
+ Rect::MakeXYWH (0 , 0 , boston->GetSize ().width , boston->GetSize ().height );
3768
+ Vector2 image_center = Vector2 (bounds.GetSize () / 2 );
3769
+ Paint paint = {.image_filter =
3770
+ ImageFilter::MakeBlur (Sigma (20.0 ), Sigma (20.0 ),
3771
+ FilterContents::BlurStyle::kNormal ,
3772
+ Entity::TileMode::kDecal )};
3773
+ Vector2 clip_size = {150 , 75 };
3774
+ Vector2 center = Vector2 (1024 , 768 ) / 2 ;
3775
+ canvas.Scale (GetContentScale ());
3776
+ canvas.ClipRect (
3777
+ Rect::MakeLTRB (center.x , center.y , center.x , center.y ).Expand (clip_size));
3778
+ canvas.Translate ({center.x , center.y , 0 });
3779
+ canvas.Scale ({0.6 , 0.6 , 1 });
3780
+ canvas.Rotate (Degrees (25 ));
3781
+
3782
+ canvas.DrawImageRect (std::make_shared<Image>(boston), /* source=*/ bounds,
3783
+ /* dest=*/ bounds.Shift (-image_center), paint);
3784
+
3785
+ ASSERT_TRUE (OpenPlaygroundHere (canvas.EndRecordingAsPicture ()));
3786
+ }
3787
+
3788
+ TEST_P (AiksTest, SubpassWithClearColorOptimization) {
3789
+ Canvas canvas;
3790
+
3791
+ // Use a non-srcOver blend mode to ensure that we don't detect this as an
3792
+ // opacity peephole optimization.
3793
+ canvas.SaveLayer (
3794
+ {.color = Color::Blue ().WithAlpha (0.5 ), .blend_mode = BlendMode::kSource },
3795
+ Rect::MakeLTRB (0 , 0 , 200 , 200 ));
3796
+ canvas.DrawPaint (
3797
+ {.color = Color::BlackTransparent (), .blend_mode = BlendMode::kSource });
3798
+ canvas.Restore ();
3799
+
3800
+ canvas.SaveLayer (
3801
+ {.color = Color::Blue (), .blend_mode = BlendMode::kDestinationOver });
3802
+ canvas.Restore ();
3803
+
3804
+ // This playground should appear blank on CI since we are only drawing
3805
+ // transparent black. If the clear color optimization is broken, the texture
3806
+ // will be filled with NaNs and may produce a magenta texture on macOS or iOS.
3807
+ ASSERT_TRUE (OpenPlaygroundHere (canvas.EndRecordingAsPicture ()));
3808
+ }
3809
+
3648
3810
} // namespace testing
3649
3811
} // namespace impeller
0 commit comments