-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Replace Impeller opacity peephole delegate with DL variant. #52707
Changes from all commits
9bdf84b
6deb635
3d5739a
326af19
d66b1a3
03f4ffb
0d36fe0
6a1a416
55ad6ee
74f8f84
49c7376
302e125
06ca207
88cd532
1f90efb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -493,30 +493,6 @@ TEST_P(AiksTest, CanEmptyPictureConvertToImage) { | |
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); | ||
} | ||
|
||
TEST_P(AiksTest, CanRenderGroupOpacity) { | ||
Canvas canvas; | ||
|
||
Paint red; | ||
red.color = Color::Red(); | ||
Paint green; | ||
green.color = Color::Green().WithAlpha(0.5); | ||
Paint blue; | ||
blue.color = Color::Blue(); | ||
|
||
Paint alpha; | ||
alpha.color = Color::Red().WithAlpha(0.5); | ||
|
||
canvas.SaveLayer(alpha); | ||
|
||
canvas.DrawRect(Rect::MakeXYWH(000, 000, 100, 100), red); | ||
canvas.DrawRect(Rect::MakeXYWH(020, 020, 100, 100), green); | ||
canvas.DrawRect(Rect::MakeXYWH(040, 040, 100, 100), blue); | ||
|
||
canvas.Restore(); | ||
|
||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); | ||
} | ||
|
||
TEST_P(AiksTest, CoordinateConversionsAreCorrect) { | ||
Canvas canvas; | ||
|
||
|
@@ -1653,45 +1629,6 @@ TEST_P(AiksTest, PaintWithFilters) { | |
ASSERT_FALSE(paint.HasColorFilter()); | ||
} | ||
|
||
TEST_P(AiksTest, OpacityPeepHoleApplicationTest) { | ||
auto entity_pass = std::make_shared<EntityPass>(); | ||
auto rect = Rect::MakeLTRB(0, 0, 100, 100); | ||
Paint paint; | ||
paint.color = Color::White().WithAlpha(0.5); | ||
paint.color_filter = | ||
ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Blue()); | ||
|
||
// Paint has color filter, can't elide. | ||
auto delegate = std::make_shared<OpacityPeepholePassDelegate>(paint); | ||
ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get())); | ||
|
||
paint.color_filter = nullptr; | ||
paint.image_filter = ImageFilter::MakeBlur(Sigma(1.0), Sigma(1.0), | ||
FilterContents::BlurStyle::kNormal, | ||
Entity::TileMode::kClamp); | ||
|
||
// Paint has image filter, can't elide. | ||
delegate = std::make_shared<OpacityPeepholePassDelegate>(paint); | ||
ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get())); | ||
|
||
paint.image_filter = nullptr; | ||
paint.color = Color::Red(); | ||
|
||
// Paint has no alpha, can't elide; | ||
delegate = std::make_shared<OpacityPeepholePassDelegate>(paint); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh? Why can't opaque colors be peepholed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just old overly defensive code. |
||
ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get())); | ||
|
||
// Positive test. | ||
Entity entity; | ||
entity.SetContents(SolidColorContents::Make( | ||
PathBuilder{}.AddRect(rect).TakePath(), Color::Red())); | ||
entity_pass->AddEntity(std::move(entity)); | ||
paint.color = Color::Red().WithAlpha(0.5); | ||
|
||
delegate = std::make_shared<OpacityPeepholePassDelegate>(paint); | ||
ASSERT_TRUE(delegate->CanCollapseIntoParentPass(entity_pass.get())); | ||
} | ||
|
||
TEST_P(AiksTest, DrawPaintAbsorbsClears) { | ||
Canvas canvas; | ||
canvas.DrawPaint({.color = Color::Red(), .blend_mode = BlendMode::kSource}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,6 @@ | |
#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" | ||
|
@@ -55,107 +54,4 @@ std::shared_ptr<FilterContents> PaintPassDelegate::WithImageFilter( | |
Entity::RenderingMode::kSubpassPrependSnapshotTransform); | ||
} | ||
|
||
/// 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 enforced bounds that clip the contents can not be safely | ||
// collapsed. | ||
if (entity_pass->GetBoundsLimitMightClipContent()) { | ||
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 || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the alpha is 0 then we should skip the pass entirely, so I'm not sure why it is saying that it "can't collapse into parent" here (i.e. return false). Also, if the paint is opaque, then that isn't a reason not to collapse the pass...? It just means you have no partial opacity to distribute, but you can still collapse it and distribute the opacity of 1.0 (i.e. NOP on modifying the opacity). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I was just being overly conservative at the time. |
||
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::kSubpassPrependSnapshotTransform); | ||
} | ||
|
||
} // namespace impeller |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be the case where I differ in assumptions. DL allows IF+opacity, but it looks like AIKS expects it to be disallowed...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We always fold the opacity into the image filter compositing, so in effect its as if the peephole wasn't applied.