| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "impeller/aiks/paint_pass_delegate.h" |
| |
| #include "impeller/core/formats.h" |
| #include "impeller/core/sampler_descriptor.h" |
| #include "impeller/entity/contents/contents.h" |
| #include "impeller/entity/contents/texture_contents.h" |
| #include "impeller/entity/entity_pass.h" |
| #include "impeller/geometry/color.h" |
| |
| namespace impeller { |
| |
| /// PaintPassDelegate |
| /// ---------------------------------------------- |
| |
| PaintPassDelegate::PaintPassDelegate(Paint paint) : paint_(std::move(paint)) {} |
| |
| // |EntityPassDelgate| |
| PaintPassDelegate::~PaintPassDelegate() = default; |
| |
| // |EntityPassDelgate| |
| bool PaintPassDelegate::CanElide() { |
| return paint_.blend_mode == BlendMode::kDestination; |
| } |
| |
| // |EntityPassDelgate| |
| bool PaintPassDelegate::CanCollapseIntoParentPass(EntityPass* entity_pass) { |
| return false; |
| } |
| |
| // |EntityPassDelgate| |
| std::shared_ptr<Contents> PaintPassDelegate::CreateContentsForSubpassTarget( |
| std::shared_ptr<Texture> target, |
| const Matrix& effect_transform) { |
| auto contents = TextureContents::MakeRect(Rect::MakeSize(target->GetSize())); |
| contents->SetTexture(target); |
| contents->SetLabel("Subpass"); |
| contents->SetSourceRect(Rect::MakeSize(target->GetSize())); |
| contents->SetOpacity(paint_.color.alpha); |
| contents->SetDeferApplyingOpacity(true); |
| |
| return paint_.WithFiltersForSubpassTarget(std::move(contents), |
| effect_transform); |
| } |
| |
| // |EntityPassDelgate| |
| std::shared_ptr<FilterContents> PaintPassDelegate::WithImageFilter( |
| const FilterInput::Variant& input, |
| const Matrix& effect_transform) const { |
| return paint_.WithImageFilter(input, effect_transform, |
| Entity::RenderingMode::kSubpass); |
| } |
| |
| /// OpacityPeepholePassDelegate |
| /// ---------------------------------------------- |
| |
| OpacityPeepholePassDelegate::OpacityPeepholePassDelegate(Paint paint) |
| : paint_(std::move(paint)) {} |
| |
| // |EntityPassDelgate| |
| OpacityPeepholePassDelegate::~OpacityPeepholePassDelegate() = default; |
| |
| // |EntityPassDelgate| |
| bool OpacityPeepholePassDelegate::CanElide() { |
| return paint_.blend_mode == BlendMode::kDestination; |
| } |
| |
| // |EntityPassDelgate| |
| bool OpacityPeepholePassDelegate::CanCollapseIntoParentPass( |
| EntityPass* entity_pass) { |
| // Passes with absorbed clips can not be safely collapsed. |
| if (entity_pass->GetBoundsLimit().has_value()) { |
| return false; |
| } |
| |
| // OpacityPeepholePassDelegate will only get used if the pass's blend mode is |
| // SourceOver, so no need to check here. |
| if (paint_.color.alpha <= 0.0 || paint_.color.alpha >= 1.0 || |
| paint_.image_filter || paint_.color_filter) { |
| return false; |
| } |
| |
| // Note: determing whether any coverage intersects has quadradic complexity in |
| // the number of rectangles, and depending on whether or not we cache at |
| // different levels of the entity tree may end up cubic. In the interest of |
| // proving whether or not this optimization is valuable, we only consider very |
| // simple peephole optimizations here - where there is a single drawing |
| // command wrapped in save layer. This would indicate something like an |
| // Opacity or FadeTransition wrapping a very simple widget, like in the |
| // CupertinoPicker. |
| if (entity_pass->GetElementCount() > 3) { |
| // Single paint command with a save layer would be: |
| // 1. clip |
| // 2. draw command |
| // 3. restore. |
| return false; |
| } |
| bool all_can_accept = true; |
| std::vector<Rect> all_coverages; |
| auto had_subpass = entity_pass->IterateUntilSubpass( |
| [&all_coverages, &all_can_accept](Entity& entity) { |
| const auto& contents = entity.GetContents(); |
| if (!entity.CanInheritOpacity()) { |
| all_can_accept = false; |
| return false; |
| } |
| auto maybe_coverage = contents->GetCoverage(entity); |
| if (maybe_coverage.has_value()) { |
| auto coverage = maybe_coverage.value(); |
| for (const auto& cv : all_coverages) { |
| if (cv.IntersectsWithRect(coverage)) { |
| all_can_accept = false; |
| return false; |
| } |
| } |
| all_coverages.push_back(coverage); |
| } |
| return true; |
| }); |
| if (had_subpass || !all_can_accept) { |
| return false; |
| } |
| auto alpha = paint_.color.alpha; |
| entity_pass->IterateUntilSubpass([&alpha](Entity& entity) { |
| entity.SetInheritedOpacity(alpha); |
| return true; |
| }); |
| return true; |
| } |
| |
| // |EntityPassDelgate| |
| std::shared_ptr<Contents> |
| OpacityPeepholePassDelegate::CreateContentsForSubpassTarget( |
| std::shared_ptr<Texture> target, |
| const Matrix& effect_transform) { |
| auto contents = TextureContents::MakeRect(Rect::MakeSize(target->GetSize())); |
| contents->SetLabel("Subpass"); |
| contents->SetTexture(target); |
| contents->SetSourceRect(Rect::MakeSize(target->GetSize())); |
| contents->SetOpacity(paint_.color.alpha); |
| contents->SetDeferApplyingOpacity(true); |
| |
| return paint_.WithFiltersForSubpassTarget(std::move(contents), |
| effect_transform); |
| } |
| |
| // |EntityPassDelgate| |
| std::shared_ptr<FilterContents> OpacityPeepholePassDelegate::WithImageFilter( |
| const FilterInput::Variant& input, |
| const Matrix& effect_transform) const { |
| return paint_.WithImageFilter(input, effect_transform, |
| Entity::RenderingMode::kSubpass); |
| } |
| |
| } // namespace impeller |