Skip to content

Commit 5d2fa4c

Browse files
authored
[Impeller] generate mipmaps for imagefilters (flutter#49794)
This resolves Jonah's feedback on flutter#49607 and Brandons feedback on flutter#49607 and flutter#49778. This avoids the need to do a lookahead by storing the proper mip count value while building the drawing on the canvas. [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 021a5ff commit 5d2fa4c

File tree

6 files changed

+48
-29
lines changed

6 files changed

+48
-29
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "impeller/aiks/testing/context_spy.h"
2323
#include "impeller/core/capture.h"
2424
#include "impeller/entity/contents/conical_gradient_contents.h"
25+
#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h"
2526
#include "impeller/entity/contents/filters/inputs/filter_input.h"
2627
#include "impeller/entity/contents/linear_gradient_contents.h"
2728
#include "impeller/entity/contents/radial_gradient_contents.h"
@@ -3757,17 +3758,7 @@ TEST_P(AiksTest, GaussianBlurSetsMipCountOnPass) {
37573758
canvas.Restore();
37583759

37593760
Picture picture = canvas.EndRecordingAsPicture();
3760-
3761-
int32_t max_mip_count = 0;
3762-
picture.pass->IterateAllElements([&](EntityPass::Element& element) -> bool {
3763-
if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
3764-
max_mip_count =
3765-
std::max(max_mip_count, subpass->get()->GetRequiredMipCount());
3766-
}
3767-
return true;
3768-
});
3769-
3770-
EXPECT_EQ(1, max_mip_count);
3761+
EXPECT_EQ(1, picture.pass->GetRequiredMipCount());
37713762
}
37723763

37733764
TEST_P(AiksTest, GaussianBlurAllocatesCorrectMipCountRenderTarget) {
@@ -3795,6 +3786,7 @@ TEST_P(AiksTest, GaussianBlurAllocatesCorrectMipCountRenderTarget) {
37953786
}
37963787

37973788
TEST_P(AiksTest, GaussianBlurMipMapNestedLayer) {
3789+
fml::testing::LogCapture log_capture;
37983790
Canvas canvas;
37993791
canvas.DrawPaint({.color = Color::Wheat()});
38003792
canvas.SaveLayer({.blend_mode = BlendMode::kMultiply});
@@ -3818,6 +3810,34 @@ TEST_P(AiksTest, GaussianBlurMipMapNestedLayer) {
38183810
std::max(it->texture->GetTextureDescriptor().mip_count, max_mip_count);
38193811
}
38203812
EXPECT_EQ(max_mip_count, 1lu);
3813+
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
3814+
std::string::npos);
3815+
}
3816+
3817+
TEST_P(AiksTest, GaussianBlurMipMapImageFilter) {
3818+
fml::testing::LogCapture log_capture;
3819+
Canvas canvas;
3820+
canvas.SaveLayer(
3821+
{.image_filter = ImageFilter::MakeBlur(Sigma(30), Sigma(30),
3822+
FilterContents::BlurStyle::kNormal,
3823+
Entity::TileMode::kClamp)});
3824+
canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});
3825+
3826+
Picture picture = canvas.EndRecordingAsPicture();
3827+
std::shared_ptr<RenderTargetCache> cache =
3828+
std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
3829+
AiksContext aiks_context(GetContext(), nullptr, cache);
3830+
picture.ToImage(aiks_context, {1024, 768});
3831+
3832+
size_t max_mip_count = 0;
3833+
for (auto it = cache->GetTextureDataBegin(); it != cache->GetTextureDataEnd();
3834+
++it) {
3835+
max_mip_count =
3836+
std::max(it->texture->GetTextureDescriptor().mip_count, max_mip_count);
3837+
}
3838+
EXPECT_EQ(max_mip_count, 1lu);
3839+
EXPECT_EQ(log_capture.str().find(GaussianBlurFilterContents::kNoMipsError),
3840+
std::string::npos);
38213841
}
38223842

38233843
} // namespace testing

impeller/aiks/canvas.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,9 @@ void Canvas::Save(bool create_subpass,
189189
subpass->SetBackdropFilter(backdrop_filter_proc);
190190
MipCountVisitor mip_count_visitor;
191191
backdrop_filter->Visit(mip_count_visitor);
192-
subpass->SetRequiredMipCount(mip_count_visitor.GetRequiredMipCount());
192+
current_pass_->SetRequiredMipCount(
193+
std::max(current_pass_->GetRequiredMipCount(),
194+
mip_count_visitor.GetRequiredMipCount()));
193195
}
194196
subpass->SetBlendMode(blend_mode);
195197
current_pass_ = GetCurrentPass().AddSubpass(std::move(subpass));
@@ -728,6 +730,12 @@ void Canvas::SaveLayer(const Paint& paint,
728730
auto& new_layer_pass = GetCurrentPass();
729731
new_layer_pass.SetBoundsLimit(bounds);
730732

733+
if (paint.image_filter) {
734+
MipCountVisitor mip_count_visitor;
735+
paint.image_filter->Visit(mip_count_visitor);
736+
new_layer_pass.SetRequiredMipCount(mip_count_visitor.GetRequiredMipCount());
737+
}
738+
731739
// Only apply opacity peephole on default blending.
732740
if (paint.blend_mode == BlendMode::kSourceOver) {
733741
new_layer_pass.SetDelegate(

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ Rect MakeReferenceUVs(const Rect& reference, const Rect& rect) {
189189
}
190190
} // namespace
191191

192+
std::string_view GaussianBlurFilterContents::kNoMipsError =
193+
"Applying gaussian blur without mipmap.";
194+
192195
GaussianBlurFilterContents::GaussianBlurFilterContents(
193196
Scalar sigma_x,
194197
Scalar sigma_y,
@@ -280,7 +283,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
280283

281284
// In order to avoid shimmering in downsampling step, we should have mips.
282285
if (input_snapshot->texture->GetMipCount() <= 1) {
283-
FML_DLOG(ERROR) << "Applying gaussian blur without mipmap.";
286+
FML_DLOG(ERROR) << kNoMipsError;
284287
}
285288
FML_DCHECK(!input_snapshot->texture->NeedsMipmapGeneration());
286289

impeller/entity/contents/filters/gaussian_blur_filter_contents.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ KernelPipeline::FragmentShader::KernelSamples GenerateBlurInfo(
2727
/// Note: This will replace `DirectionalGaussianBlurFilterContents`.
2828
class GaussianBlurFilterContents final : public FilterContents {
2929
public:
30+
static std::string_view kNoMipsError;
31+
3032
explicit GaussianBlurFilterContents(Scalar sigma_x,
3133
Scalar sigma_y,
3234
Entity::TileMode tile_mode);

impeller/entity/entity_pass.cc

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ bool EntityPass::Render(ContentContext& renderer,
344344
if (reads_from_onscreen_backdrop) {
345345
EntityPassTarget offscreen_target = CreateRenderTarget(
346346
renderer, root_render_target.GetRenderTargetSize(),
347-
GetBackdropFilterMipCount(),
347+
GetRequiredMipCount(),
348348
GetClearColorOrDefault(render_target.GetRenderTargetSize()));
349349

350350
if (!OnRender(renderer, // renderer
@@ -606,7 +606,7 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
606606
auto subpass_target = CreateRenderTarget(
607607
renderer, // renderer
608608
subpass_size, // size
609-
subpass->GetBackdropFilterMipCount(),
609+
subpass->GetRequiredMipCount(),
610610
subpass->GetClearColorOrDefault(subpass_size)); // clear_color
611611

612612
if (!subpass_target.IsValid()) {
@@ -1191,16 +1191,6 @@ void EntityPass::SetEnableOffscreenCheckerboard(bool enabled) {
11911191
enable_offscreen_debug_checkerboard_ = enabled;
11921192
}
11931193

1194-
int32_t EntityPass::GetBackdropFilterMipCount() const {
1195-
int32_t result = 1;
1196-
for (auto& element : elements_) {
1197-
if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
1198-
result = std::max(result, subpass->get()->GetRequiredMipCount());
1199-
}
1200-
}
1201-
return result;
1202-
}
1203-
12041194
EntityPassClipRecorder::EntityPassClipRecorder() {}
12051195

12061196
void EntityPassClipRecorder::RecordEntity(const Entity& entity,

impeller/entity/entity_pass.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,6 @@ class EntityPass {
157157
required_mip_count_ = mip_count;
158158
}
159159

160-
/// Returns the mip map count that should be required for the render target
161-
/// receiving this EntityPass.
162-
int32_t GetBackdropFilterMipCount() const;
163-
164160
//----------------------------------------------------------------------------
165161
/// @brief Computes the coverage of a given subpass. This is used to
166162
/// determine the texture size of a given subpass before it's rendered

0 commit comments

Comments
 (0)