From 56aa10f9157111c21c019fcf1e8346cce70a5c0c Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 12 Jan 2024 15:28:27 -0800 Subject: [PATCH 1/2] [Impeller] fixed nested save layer mipmap counts --- impeller/aiks/aiks_unittests.cc | 26 ++++++++++++++++++++++ impeller/entity/entity_pass.cc | 39 +++++++++++++++++---------------- impeller/entity/entity_pass.h | 4 ++++ 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index c2b07397610a1..3858ff0dca914 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -3794,5 +3794,31 @@ TEST_P(AiksTest, GaussianBlurAllocatesCorrectMipCountRenderTarget) { 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 cache = + std::make_shared(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 576c3a97a6ff9..e33171fae94b2 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -325,23 +325,13 @@ bool EntityPass::Render(ContentContext& renderer, 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(&element)) { - if (const auto& contents = entity->GetContents()) { - contents->PopulateGlyphAtlas(lazy_glyph_atlas, - entity->DeriveTextScale()); - } - } - if (auto subpass = std::get_if>(&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 @@ bool EntityPass::Render(ContentContext& renderer, // 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(), + GetChildrenRequiredMipCount(), GetClearColorOrDefault(render_target.GetRenderTargetSize())); if (!OnRender(renderer, // renderer @@ -615,7 +606,7 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( auto subpass_target = CreateRenderTarget( renderer, // renderer subpass_size, // size - /*mip_count=*/1, + subpass->GetChildrenRequiredMipCount(), subpass->GetClearColorOrDefault(subpass_size)); // clear_color if (!subpass_target.IsValid()) { @@ -1200,6 +1191,16 @@ void EntityPass::SetEnableOffscreenCheckerboard(bool enabled) { enable_offscreen_debug_checkerboard_ = enabled; } +int32_t EntityPass::GetChildrenRequiredMipCount() const { + int32_t result = 1; + for (auto& element : elements_) { + if (auto subpass = std::get_if>(&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 7de68d0d9ad11..b6c494f12e4ee 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -157,6 +157,10 @@ class EntityPass { required_mip_count_ = mip_count; } + /// Returns the mip map count that should be required for the render target + /// receiving this EntityPass. + int32_t GetChildrenRequiredMipCount() 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 From ff6950c39087559fb79b7c214ca01cb741141865 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 12 Jan 2024 16:52:54 -0800 Subject: [PATCH 2/2] rename to GetBackdropFilterMipCount --- impeller/entity/entity_pass.cc | 6 +++--- impeller/entity/entity_pass.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index e33171fae94b2..dec9a98b15ed7 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -344,7 +344,7 @@ bool EntityPass::Render(ContentContext& renderer, if (reads_from_onscreen_backdrop) { EntityPassTarget offscreen_target = CreateRenderTarget( renderer, root_render_target.GetRenderTargetSize(), - GetChildrenRequiredMipCount(), + GetBackdropFilterMipCount(), GetClearColorOrDefault(render_target.GetRenderTargetSize())); if (!OnRender(renderer, // renderer @@ -606,7 +606,7 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( auto subpass_target = CreateRenderTarget( renderer, // renderer subpass_size, // size - subpass->GetChildrenRequiredMipCount(), + subpass->GetBackdropFilterMipCount(), subpass->GetClearColorOrDefault(subpass_size)); // clear_color if (!subpass_target.IsValid()) { @@ -1191,7 +1191,7 @@ void EntityPass::SetEnableOffscreenCheckerboard(bool enabled) { enable_offscreen_debug_checkerboard_ = enabled; } -int32_t EntityPass::GetChildrenRequiredMipCount() const { +int32_t EntityPass::GetBackdropFilterMipCount() const { int32_t result = 1; for (auto& element : elements_) { if (auto subpass = std::get_if>(&element)) { diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index b6c494f12e4ee..cacf45776c029 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -159,7 +159,7 @@ class EntityPass { /// Returns the mip map count that should be required for the render target /// receiving this EntityPass. - int32_t GetChildrenRequiredMipCount() const; + int32_t GetBackdropFilterMipCount() const; //---------------------------------------------------------------------------- /// @brief Computes the coverage of a given subpass. This is used to