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

Commit 41e4b39

Browse files
authored
Reland: [Impeller] Use downsample shader for blur instead of mip levels. (#54149)
relands #53760 reverted in #54148 The fix for this was found with the help of Jonah. Part of a series of gaussian blur changes: 1) #54148 1) #54116 1) #54150 1) #54149 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 8a551eb commit 41e4b39

10 files changed

+346
-263
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42203,6 +42203,7 @@ ORIGIN: ../../../flutter/impeller/entity/shaders/rrect_blur.vert + ../../../flut
4220342203
ORIGIN: ../../../flutter/impeller/entity/shaders/runtime_effect.vert + ../../../flutter/LICENSE
4220442204
ORIGIN: ../../../flutter/impeller/entity/shaders/solid_fill.frag + ../../../flutter/LICENSE
4220542205
ORIGIN: ../../../flutter/impeller/entity/shaders/solid_fill.vert + ../../../flutter/LICENSE
42206+
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_downsample.frag + ../../../flutter/LICENSE
4220642207
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_fill.frag + ../../../flutter/LICENSE
4220742208
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_fill.vert + ../../../flutter/LICENSE
4220842209
ORIGIN: ../../../flutter/impeller/entity/shaders/texture_fill_strict_src.frag + ../../../flutter/LICENSE
@@ -45083,6 +45084,7 @@ FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert
4508345084
FILE: ../../../flutter/impeller/entity/shaders/runtime_effect.vert
4508445085
FILE: ../../../flutter/impeller/entity/shaders/solid_fill.frag
4508545086
FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert
45087+
FILE: ../../../flutter/impeller/entity/shaders/texture_downsample.frag
4508645088
FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag
4508745089
FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert
4508845090
FILE: ../../../flutter/impeller/entity/shaders/texture_fill_strict_src.frag

impeller/aiks/aiks_blur_unittests.cc

Lines changed: 0 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,160 +1041,6 @@ TEST_P(AiksTest, GuassianBlurUpdatesMipmapContents) {
10411041
ASSERT_TRUE(OpenPlaygroundHere(callback));
10421042
}
10431043

1044-
TEST_P(AiksTest, GaussianBlurSetsMipCountOnPass) {
1045-
Canvas canvas;
1046-
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
1047-
canvas.SaveLayer({}, std::nullopt,
1048-
ImageFilter::MakeBlur(Sigma(3), Sigma(3),
1049-
FilterContents::BlurStyle::kNormal,
1050-
Entity::TileMode::kClamp));
1051-
canvas.Restore();
1052-
1053-
Picture picture = canvas.EndRecordingAsPicture();
1054-
EXPECT_EQ(4, picture.pass->GetRequiredMipCount());
1055-
}
1056-
1057-
TEST_P(AiksTest, GaussianBlurAllocatesCorrectMipCountRenderTarget) {
1058-
size_t blur_required_mip_count =
1059-
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
1060-
1061-
Canvas canvas;
1062-
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
1063-
canvas.SaveLayer({}, std::nullopt,
1064-
ImageFilter::MakeBlur(Sigma(3), Sigma(3),
1065-
FilterContents::BlurStyle::kNormal,
1066-
Entity::TileMode::kClamp));
1067-
canvas.Restore();
1068-
1069-
Picture picture = canvas.EndRecordingAsPicture();
1070-
std::shared_ptr<RenderTargetCache> cache =
1071-
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
1072-
AiksContext aiks_context(GetContext(), nullptr, cache);
1073-
picture.ToImage(aiks_context, {100, 100});
1074-
1075-
size_t max_mip_count = 0;
1076-
for (auto it = cache->GetRenderTargetDataBegin();
1077-
it != cache->GetRenderTargetDataEnd(); ++it) {
1078-
max_mip_count = std::max(it->config.mip_count, max_mip_count);
1079-
}
1080-
EXPECT_EQ(max_mip_count, blur_required_mip_count);
1081-
}
1082-
1083-
TEST_P(AiksTest, GaussianBlurMipMapNestedLayer) {
1084-
fml::testing::LogCapture log_capture;
1085-
size_t blur_required_mip_count =
1086-
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
1087-
1088-
Canvas canvas;
1089-
canvas.DrawPaint({.color = Color::Wheat()});
1090-
canvas.SaveLayer({.blend_mode = BlendMode::kMultiply});
1091-
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
1092-
canvas.SaveLayer({}, std::nullopt,
1093-
ImageFilter::MakeBlur(Sigma(30), Sigma(30),
1094-
FilterContents::BlurStyle::kNormal,
1095-
Entity::TileMode::kClamp));
1096-
canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});
1097-
1098-
Picture picture = canvas.EndRecordingAsPicture();
1099-
std::shared_ptr<RenderTargetCache> cache =
1100-
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
1101-
AiksContext aiks_context(GetContext(), nullptr, cache);
1102-
picture.ToImage(aiks_context, {100, 100});
1103-
1104-
size_t max_mip_count = 0;
1105-
for (auto it = cache->GetRenderTargetDataBegin();
1106-
it != cache->GetRenderTargetDataEnd(); ++it) {
1107-
max_mip_count = std::max(it->config.mip_count, max_mip_count);
1108-
}
1109-
EXPECT_EQ(max_mip_count, blur_required_mip_count);
1110-
// The log is FML_DLOG, so only check in debug builds.
1111-
#ifndef NDEBUG
1112-
if (GetParam() != PlaygroundBackend::kOpenGLES) {
1113-
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1114-
std::string::npos);
1115-
} else {
1116-
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1117-
std::string::npos);
1118-
}
1119-
#endif
1120-
}
1121-
1122-
TEST_P(AiksTest, GaussianBlurMipMapImageFilter) {
1123-
size_t blur_required_mip_count =
1124-
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
1125-
fml::testing::LogCapture log_capture;
1126-
Canvas canvas;
1127-
canvas.SaveLayer(
1128-
{.image_filter = ImageFilter::MakeBlur(Sigma(30), Sigma(30),
1129-
FilterContents::BlurStyle::kNormal,
1130-
Entity::TileMode::kClamp)});
1131-
canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});
1132-
1133-
Picture picture = canvas.EndRecordingAsPicture();
1134-
std::shared_ptr<RenderTargetCache> cache =
1135-
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
1136-
AiksContext aiks_context(GetContext(), nullptr, cache);
1137-
picture.ToImage(aiks_context, {1024, 768});
1138-
1139-
size_t max_mip_count = 0;
1140-
for (auto it = cache->GetRenderTargetDataBegin();
1141-
it != cache->GetRenderTargetDataEnd(); ++it) {
1142-
max_mip_count = std::max(it->config.mip_count, max_mip_count);
1143-
}
1144-
EXPECT_EQ(max_mip_count, blur_required_mip_count);
1145-
// The log is FML_DLOG, so only check in debug builds.
1146-
#ifndef NDEBUG
1147-
if (GetParam() != PlaygroundBackend::kOpenGLES) {
1148-
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1149-
std::string::npos);
1150-
} else {
1151-
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1152-
std::string::npos);
1153-
}
1154-
#endif
1155-
}
1156-
1157-
TEST_P(AiksTest, GaussianBlurMipMapSolidColor) {
1158-
size_t blur_required_mip_count =
1159-
GetParam() == PlaygroundBackend::kOpenGLES ? 1 : 4;
1160-
fml::testing::LogCapture log_capture;
1161-
Canvas canvas;
1162-
canvas.DrawPath(PathBuilder{}
1163-
.MoveTo({100, 100})
1164-
.LineTo({200, 100})
1165-
.LineTo({150, 200})
1166-
.LineTo({50, 200})
1167-
.Close()
1168-
.TakePath(),
1169-
{.color = Color::Chartreuse(),
1170-
.image_filter = ImageFilter::MakeBlur(
1171-
Sigma(30), Sigma(30), FilterContents::BlurStyle::kNormal,
1172-
Entity::TileMode::kClamp)});
1173-
1174-
Picture picture = canvas.EndRecordingAsPicture();
1175-
std::shared_ptr<RenderTargetCache> cache =
1176-
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
1177-
AiksContext aiks_context(GetContext(), nullptr, cache);
1178-
picture.ToImage(aiks_context, {1024, 768});
1179-
1180-
size_t max_mip_count = 0;
1181-
for (auto it = cache->GetRenderTargetDataBegin();
1182-
it != cache->GetRenderTargetDataEnd(); ++it) {
1183-
max_mip_count = std::max(it->config.mip_count, max_mip_count);
1184-
}
1185-
EXPECT_EQ(max_mip_count, blur_required_mip_count);
1186-
// The log is FML_DLOG, so only check in debug builds.
1187-
#ifndef NDEBUG
1188-
if (GetParam() != PlaygroundBackend::kOpenGLES) {
1189-
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1190-
std::string::npos);
1191-
} else {
1192-
EXPECT_NE(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
1193-
std::string::npos);
1194-
}
1195-
#endif
1196-
}
1197-
11981044
TEST_P(AiksTest, MaskBlurDoesntStretchContents) {
11991045
Scalar sigma = 70;
12001046
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {

impeller/aiks/canvas.cc

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -185,37 +185,6 @@ void Canvas::Save(uint32_t total_content_depth) {
185185
Save(false, total_content_depth);
186186
}
187187

188-
namespace {
189-
class MipCountVisitor : public ImageFilterVisitor {
190-
public:
191-
virtual void Visit(const BlurImageFilter& filter) {
192-
required_mip_count_ = FilterContents::kBlurFilterRequiredMipCount;
193-
}
194-
virtual void Visit(const LocalMatrixImageFilter& filter) {
195-
required_mip_count_ = 1;
196-
}
197-
virtual void Visit(const DilateImageFilter& filter) {
198-
required_mip_count_ = 1;
199-
}
200-
virtual void Visit(const ErodeImageFilter& filter) {
201-
required_mip_count_ = 1;
202-
}
203-
virtual void Visit(const MatrixImageFilter& filter) {
204-
required_mip_count_ = 1;
205-
}
206-
virtual void Visit(const ComposeImageFilter& filter) {
207-
required_mip_count_ = 1;
208-
}
209-
virtual void Visit(const ColorImageFilter& filter) {
210-
required_mip_count_ = 1;
211-
}
212-
int32_t GetRequiredMipCount() const { return required_mip_count_; }
213-
214-
private:
215-
int32_t required_mip_count_ = -1;
216-
};
217-
} // namespace
218-
219188
void Canvas::Save(bool create_subpass,
220189
uint32_t total_content_depth,
221190
BlendMode blend_mode,
@@ -240,11 +209,6 @@ void Canvas::Save(bool create_subpass,
240209
return filter;
241210
};
242211
subpass->SetBackdropFilter(backdrop_filter_proc);
243-
MipCountVisitor mip_count_visitor;
244-
backdrop_filter->Visit(mip_count_visitor);
245-
current_pass_->SetRequiredMipCount(
246-
std::max(current_pass_->GetRequiredMipCount(),
247-
mip_count_visitor.GetRequiredMipCount()));
248212
}
249213
subpass->SetBlendMode(blend_mode);
250214
current_pass_ = GetCurrentPass().AddSubpass(std::move(subpass));
@@ -873,11 +837,6 @@ void Canvas::SaveLayer(const Paint& paint,
873837
new_layer_pass.SetBoundsLimit(bounds, bounds_promise);
874838
}
875839

876-
if (paint.image_filter) {
877-
MipCountVisitor mip_count_visitor;
878-
paint.image_filter->Visit(mip_count_visitor);
879-
new_layer_pass.SetRequiredMipCount(mip_count_visitor.GetRequiredMipCount());
880-
}
881840
// When applying a save layer, absorb any pending distributed opacity.
882841
Paint paint_copy = paint;
883842
paint_copy.color.alpha *= transform_stack_.back().distributed_opacity;

impeller/entity/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ impeller_shaders("entity_shaders") {
5050
"shaders/blending/vertices_uber.frag",
5151
"shaders/gradients/fast_gradient.vert",
5252
"shaders/gradients/fast_gradient.frag",
53+
"shaders/texture_downsample.frag",
5354
]
5455
}
5556

impeller/entity/contents/content_context.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ ContentContext::ContentContext(
428428
{static_cast<Scalar>(BlendSelectValues::kSoftLight), supports_decal});
429429
}
430430

431+
texture_downsample_pipelines_.CreateDefault(*context_, options_trianglestrip);
431432
rrect_blur_pipelines_.CreateDefault(*context_, options_trianglestrip);
432433
texture_strict_src_pipelines_.CreateDefault(*context_, options);
433434
tiled_texture_pipelines_.CreateDefault(*context_, options, {supports_decal});

impeller/entity/contents/content_context.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "impeller/entity/solid_fill.vert.h"
4949
#include "impeller/entity/srgb_to_linear_filter.frag.h"
5050
#include "impeller/entity/sweep_gradient_fill.frag.h"
51+
#include "impeller/entity/texture_downsample.frag.h"
5152
#include "impeller/entity/texture_fill.frag.h"
5253
#include "impeller/entity/texture_fill.vert.h"
5354
#include "impeller/entity/texture_fill_strict_src.frag.h"
@@ -110,6 +111,9 @@ using RRectBlurPipeline =
110111
RenderPipelineHandle<RrectBlurVertexShader, RrectBlurFragmentShader>;
111112
using TexturePipeline =
112113
RenderPipelineHandle<TextureFillVertexShader, TextureFillFragmentShader>;
114+
using TextureDownsamplePipeline =
115+
RenderPipelineHandle<TextureFillVertexShader,
116+
TextureDownsampleFragmentShader>;
113117
using TextureStrictSrcPipeline =
114118
RenderPipelineHandle<TextureFillVertexShader,
115119
TextureFillStrictSrcFragmentShader>;
@@ -590,6 +594,11 @@ class ContentContext {
590594
return GetPipeline(blend_softlight_pipelines_, opts);
591595
}
592596

597+
std::shared_ptr<Pipeline<PipelineDescriptor>> GetDownsamplePipeline(
598+
ContentContextOptions opts) const {
599+
return GetPipeline(texture_downsample_pipelines_, opts);
600+
}
601+
593602
// Framebuffer Advanced Blends
594603
std::shared_ptr<Pipeline<PipelineDescriptor>>
595604
GetFramebufferBlendColorPipeline(ContentContextOptions opts) const {
@@ -881,6 +890,7 @@ class ContentContext {
881890
sweep_gradient_ssbo_fill_pipelines_;
882891
mutable Variants<RRectBlurPipeline> rrect_blur_pipelines_;
883892
mutable Variants<TexturePipeline> texture_pipelines_;
893+
mutable Variants<TextureDownsamplePipeline> texture_downsample_pipelines_;
884894
mutable Variants<TextureStrictSrcPipeline> texture_strict_src_pipelines_;
885895
#ifdef IMPELLER_ENABLE_OPENGLES
886896
mutable Variants<TiledTextureExternalPipeline>

0 commit comments

Comments
 (0)