[Impeller] fixed nested save layer mipmap counts (#49778)
resolves https://github.com/flutter/engine/pull/49607#discussion_r1450982660
[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc
index c2b0739..3858ff0 100644
--- a/impeller/aiks/aiks_unittests.cc
+++ b/impeller/aiks/aiks_unittests.cc
@@ -3794,5 +3794,31 @@
EXPECT_EQ(max_mip_count, 1lu);
}
+TEST_P(AiksTest, GaussianBlurMipMapNestedLayer) {
+ Canvas canvas;
+ canvas.DrawPaint({.color = Color::Wheat()});
+ canvas.SaveLayer({.blend_mode = BlendMode::kMultiply});
+ canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
+ canvas.SaveLayer({}, std::nullopt,
+ ImageFilter::MakeBlur(Sigma(30), Sigma(30),
+ FilterContents::BlurStyle::kNormal,
+ Entity::TileMode::kClamp));
+ canvas.DrawCircle({200, 200}, 50, {.color = Color::Chartreuse()});
+
+ Picture picture = canvas.EndRecordingAsPicture();
+ std::shared_ptr<RenderTargetCache> cache =
+ std::make_shared<RenderTargetCache>(GetContext()->GetResourceAllocator());
+ AiksContext aiks_context(GetContext(), nullptr, cache);
+ picture.ToImage(aiks_context, {100, 100});
+
+ size_t max_mip_count = 0;
+ for (auto it = cache->GetTextureDataBegin(); it != cache->GetTextureDataEnd();
+ ++it) {
+ max_mip_count =
+ std::max(it->texture->GetTextureDescriptor().mip_count, max_mip_count);
+ }
+ EXPECT_EQ(max_mip_count, 1lu);
+}
+
} // namespace testing
} // namespace impeller
diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc
index 576c3a9..dec9a98 100644
--- a/impeller/entity/entity_pass.cc
+++ b/impeller/entity/entity_pass.cc
@@ -325,23 +325,13 @@
Rect::MakeSize(root_render_target.GetRenderTargetSize()),
{.readonly = true});
- int32_t required_mip_count = 1;
- IterateAllElements(
- [&required_mip_count, lazy_glyph_atlas = renderer.GetLazyGlyphAtlas()](
- const Element& element) {
- if (auto entity = std::get_if<Entity>(&element)) {
- if (const auto& contents = entity->GetContents()) {
- contents->PopulateGlyphAtlas(lazy_glyph_atlas,
- entity->DeriveTextScale());
- }
- }
- if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
- const EntityPass* entity_pass = subpass->get();
- required_mip_count =
- std::max(required_mip_count, entity_pass->GetRequiredMipCount());
- }
- return true;
- });
+ IterateAllEntities([lazy_glyph_atlas =
+ renderer.GetLazyGlyphAtlas()](const Entity& entity) {
+ if (const auto& contents = entity.GetContents()) {
+ contents->PopulateGlyphAtlas(lazy_glyph_atlas, entity.DeriveTextScale());
+ }
+ return true;
+ });
ClipCoverageStack clip_coverage_stack = {ClipCoverageLayer{
.coverage = Rect::MakeSize(root_render_target.GetRenderTargetSize()),
@@ -353,7 +343,8 @@
// there's no need to set up a stencil attachment on the root render target.
if (reads_from_onscreen_backdrop) {
EntityPassTarget offscreen_target = CreateRenderTarget(
- renderer, root_render_target.GetRenderTargetSize(), required_mip_count,
+ renderer, root_render_target.GetRenderTargetSize(),
+ GetBackdropFilterMipCount(),
GetClearColorOrDefault(render_target.GetRenderTargetSize()));
if (!OnRender(renderer, // renderer
@@ -615,7 +606,7 @@
auto subpass_target = CreateRenderTarget(
renderer, // renderer
subpass_size, // size
- /*mip_count=*/1,
+ subpass->GetBackdropFilterMipCount(),
subpass->GetClearColorOrDefault(subpass_size)); // clear_color
if (!subpass_target.IsValid()) {
@@ -1200,6 +1191,16 @@
enable_offscreen_debug_checkerboard_ = enabled;
}
+int32_t EntityPass::GetBackdropFilterMipCount() const {
+ int32_t result = 1;
+ for (auto& element : elements_) {
+ if (auto subpass = std::get_if<std::unique_ptr<EntityPass>>(&element)) {
+ result = std::max(result, subpass->get()->GetRequiredMipCount());
+ }
+ }
+ return result;
+}
+
EntityPassClipRecorder::EntityPassClipRecorder() {}
void EntityPassClipRecorder::RecordEntity(const Entity& entity,
diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h
index 7de68d0..cacf457 100644
--- a/impeller/entity/entity_pass.h
+++ b/impeller/entity/entity_pass.h
@@ -157,6 +157,10 @@
required_mip_count_ = mip_count;
}
+ /// Returns the mip map count that should be required for the render target
+ /// receiving this EntityPass.
+ int32_t GetBackdropFilterMipCount() const;
+
//----------------------------------------------------------------------------
/// @brief Computes the coverage of a given subpass. This is used to
/// determine the texture size of a given subpass before it's rendered