Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 68f1d69

Browse files
authored
[Impeller] moved tests to aiks_blur_unittests, added warning (#51274)
issue: flutter/flutter#140106 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
1 parent bbb1ed0 commit 68f1d69

File tree

2 files changed

+193
-183
lines changed

2 files changed

+193
-183
lines changed

impeller/aiks/aiks_blur_unittests.cc

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "flutter/impeller/aiks/aiks_unittests.h"
66

77
#include "impeller/aiks/canvas.h"
8+
#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h"
89
#include "impeller/entity/render_target_cache.h"
910
#include "impeller/geometry/path_builder.h"
1011
#include "impeller/playground/widgets.h"
@@ -672,5 +673,187 @@ TEST_P(AiksTest, GaussianBlurStyleSolid) {
672673
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
673674
}
674675

676+
TEST_P(AiksTest, GuassianBlurUpdatesMipmapContents) {
677+
// This makes sure if mip maps are recycled across invocations of blurs the
678+
// contents get updated each frame correctly. If they aren't updated the color
679+
// inside the blur and outside the blur will be different.
680+
//
681+
// If there is some change to render target caching this could display a false
682+
// positive in the future. Also, if the LOD that is rendered is 1 it could
683+
// present a false positive.
684+
int32_t count = 0;
685+
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
686+
Canvas canvas;
687+
if (count++ == 0) {
688+
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
689+
} else {
690+
canvas.DrawCircle({100, 100}, 50, {.color = Color::Chartreuse()});
691+
}
692+
canvas.ClipRRect(Rect::MakeLTRB(75, 50, 375, 275), {20, 20});
693+
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
694+
ImageFilter::MakeBlur(Sigma(30.0), Sigma(30.0),
695+
FilterContents::BlurStyle::kNormal,
696+
Entity::TileMode::kClamp));
697+
canvas.Restore();
698+
return canvas.EndRecordingAsPicture();
699+
};
700+
701+
ASSERT_TRUE(OpenPlaygroundHere(callback));
702+
}
703+
704+
TEST_P(AiksTest, GaussianBlurSetsMipCountOnPass) {
705+
Canvas canvas;
706+
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
707+
canvas.SaveLayer({}, std::nullopt,
708+
ImageFilter::MakeBlur(Sigma(3), Sigma(3),
709+
FilterContents::BlurStyle::kNormal,
710+
Entity::TileMode::kClamp));
711+
canvas.Restore();
712+
713+
Picture picture = canvas.EndRecordingAsPicture();
714+
EXPECT_EQ(4, picture.pass->GetRequiredMipCount());
715+
}
716+
717+
TEST_P(AiksTest, GaussianBlurAllocatesCorrectMipCountRenderTarget) {
718+
size_t blur_required_mip_count =
719+
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
720+
721+
Canvas canvas;
722+
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
723+
canvas.SaveLayer({}, std::nullopt,
724+
ImageFilter::MakeBlur(Sigma(3), Sigma(3),
725+
FilterContents::BlurStyle::kNormal,
726+
Entity::TileMode::kClamp));
727+
canvas.Restore();
728+
729+
Picture picture = canvas.EndRecordingAsPicture();
730+
std::shared_ptr<RenderTargetCache> cache =
731+
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
732+
AiksContext aiks_context(GetContext(), nullptr, cache);
733+
picture.ToImage(aiks_context, {100, 100});
734+
735+
size_t max_mip_count = 0;
736+
for (auto it = cache->GetRenderTargetDataBegin();
737+
it != cache->GetRenderTargetDataEnd(); ++it) {
738+
max_mip_count = std::max(it->config.mip_count, max_mip_count);
739+
}
740+
EXPECT_EQ(max_mip_count, blur_required_mip_count);
741+
}
742+
743+
TEST_P(AiksTest, GaussianBlurMipMapNestedLayer) {
744+
fml::testing::LogCapture log_capture;
745+
size_t blur_required_mip_count =
746+
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
747+
748+
Canvas canvas;
749+
canvas.DrawPaint({.color = Color::Wheat()});
750+
canvas.SaveLayer({.blend_mode = BlendMode::kMultiply});
751+
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
752+
canvas.SaveLayer({}, std::nullopt,
753+
ImageFilter::MakeBlur(Sigma(30), Sigma(30),
754+
FilterContents::BlurStyle::kNormal,
755+
Entity::TileMode::kClamp));
756+
canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});
757+
758+
Picture picture = canvas.EndRecordingAsPicture();
759+
std::shared_ptr<RenderTargetCache> cache =
760+
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
761+
AiksContext aiks_context(GetContext(), nullptr, cache);
762+
picture.ToImage(aiks_context, {100, 100});
763+
764+
size_t max_mip_count = 0;
765+
for (auto it = cache->GetRenderTargetDataBegin();
766+
it != cache->GetRenderTargetDataEnd(); ++it) {
767+
max_mip_count = std::max(it->config.mip_count, max_mip_count);
768+
}
769+
EXPECT_EQ(max_mip_count, blur_required_mip_count);
770+
// The log is FML_DLOG, so only check in debug builds.
771+
#ifndef NDEBUG
772+
if (GetParam() != PlaygroundBackend::kOpenGLES) {
773+
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
774+
std::string::npos);
775+
} else {
776+
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
777+
std::string::npos);
778+
}
779+
#endif
780+
}
781+
782+
TEST_P(AiksTest, GaussianBlurMipMapImageFilter) {
783+
size_t blur_required_mip_count =
784+
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
785+
fml::testing::LogCapture log_capture;
786+
Canvas canvas;
787+
canvas.SaveLayer(
788+
{.image_filter = ImageFilter::MakeBlur(Sigma(30), Sigma(30),
789+
FilterContents::BlurStyle::kNormal,
790+
Entity::TileMode::kClamp)});
791+
canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});
792+
793+
Picture picture = canvas.EndRecordingAsPicture();
794+
std::shared_ptr<RenderTargetCache> cache =
795+
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
796+
AiksContext aiks_context(GetContext(), nullptr, cache);
797+
picture.ToImage(aiks_context, {1024, 768});
798+
799+
size_t max_mip_count = 0;
800+
for (auto it = cache->GetRenderTargetDataBegin();
801+
it != cache->GetRenderTargetDataEnd(); ++it) {
802+
max_mip_count = std::max(it->config.mip_count, max_mip_count);
803+
}
804+
EXPECT_EQ(max_mip_count, blur_required_mip_count);
805+
// The log is FML_DLOG, so only check in debug builds.
806+
#ifndef NDEBUG
807+
if (GetParam() != PlaygroundBackend::kOpenGLES) {
808+
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
809+
std::string::npos);
810+
} else {
811+
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
812+
std::string::npos);
813+
}
814+
#endif
815+
}
816+
817+
TEST_P(AiksTest, GaussianBlurMipMapSolidColor) {
818+
size_t blur_required_mip_count =
819+
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
820+
fml::testing::LogCapture log_capture;
821+
Canvas canvas;
822+
canvas.DrawPath(PathBuilder{}
823+
.MoveTo({100, 100})
824+
.LineTo({200, 100})
825+
.LineTo({150, 200})
826+
.LineTo({50, 200})
827+
.Close()
828+
.TakePath(),
829+
{.color = Color::Chartreuse(),
830+
.image_filter = ImageFilter::MakeBlur(
831+
Sigma(30), Sigma(30), FilterContents::BlurStyle::kNormal,
832+
Entity::TileMode::kClamp)});
833+
834+
Picture picture = canvas.EndRecordingAsPicture();
835+
std::shared_ptr<RenderTargetCache> cache =
836+
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
837+
AiksContext aiks_context(GetContext(), nullptr, cache);
838+
picture.ToImage(aiks_context, {1024, 768});
839+
840+
size_t max_mip_count = 0;
841+
for (auto it = cache->GetRenderTargetDataBegin();
842+
it != cache->GetRenderTargetDataEnd(); ++it) {
843+
max_mip_count = std::max(it->config.mip_count, max_mip_count);
844+
}
845+
EXPECT_EQ(max_mip_count, blur_required_mip_count);
846+
// The log is FML_DLOG, so only check in debug builds.
847+
#ifndef NDEBUG
848+
if (GetParam() != PlaygroundBackend::kOpenGLES) {
849+
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
850+
std::string::npos);
851+
} else {
852+
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
853+
std::string::npos);
854+
}
855+
#endif
856+
}
857+
675858
} // namespace testing
676859
} // namespace impeller

0 commit comments

Comments
 (0)