diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index be7b50c8cb347..44a27de5286ec 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -2264,6 +2264,30 @@ TEST_P(AiksTest, DrawPaintAbsorbsClears) { ASSERT_EQ(render_pass->GetCommands().size(), 0llu); } +// This is important to enforce with texture reuse, since cached textures need +// to be cleared before reuse. +TEST_P(AiksTest, + ParentSaveLayerCreatesRenderPassWhenChildBackdropFilterIsPresent) { + Canvas canvas; + canvas.SaveLayer({}, std::nullopt, ImageFilter::MakeMatrix(Matrix(), {})); + canvas.DrawPaint({.color = Color::Red(), .blend_mode = BlendMode::kSource}); + canvas.DrawPaint({.color = Color::CornflowerBlue().WithAlpha(0.75), + .blend_mode = BlendMode::kSourceOver}); + canvas.Restore(); + + Picture picture = canvas.EndRecordingAsPicture(); + + std::shared_ptr spy = ContextSpy::Make(); + std::shared_ptr real_context = GetContext(); + std::shared_ptr mock_context = spy->MakeContext(real_context); + AiksContext renderer(mock_context, nullptr); + std::shared_ptr image = picture.ToImage(renderer, {300, 300}); + + ASSERT_EQ(spy->render_passes_.size(), 3llu); + std::shared_ptr render_pass = spy->render_passes_[0]; + ASSERT_EQ(render_pass->GetCommands().size(), 0llu); +} + TEST_P(AiksTest, DrawRectAbsorbsClears) { Canvas canvas; canvas.DrawRect({0, 0, 300, 300}, diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 6b4017ad0a19c..563bcf4ef7abb 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -534,6 +534,14 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( proc(FilterInput::Make(std::move(texture)), subpass->xformation_.Basis(), Entity::RenderingMode::kSubpass); + // If the very first thing we render in this EntityPass is a subpass that + // happens to have a backdrop filter, than that backdrop filter will end + // may wind up sampling from the raw, uncleared texture that came straight + // out of the texture cache. By calling `pass_context.GetRenderPass` here, + // we force the texture to pass through at least one RenderPass with the + // correct clear configuration before any sampling occurs. + pass_context.GetRenderPass(pass_depth); + // The subpass will need to read from the current pass texture when // rendering the backdrop, so if there's an active pass, end it prior to // rendering the subpass.