[DisplayList] Disable group opacity when a RuntimeEffect is in use (flutter/engine#56936)
Fixes https://github.com/flutter/flutter/issues/158500 Impeller does not support group opacity for RuntimeEffects so we disable the optimization with a flag when it is detected.
This commit is contained in:
parent
72d1c2fea6
commit
1c2cd45f88
@ -1367,7 +1367,7 @@ TEST_F(DisplayListTest, SaveLayerFalseWithSrcBlendSupportsGroupOpacity) {
|
|||||||
DisplayListBuilder builder;
|
DisplayListBuilder builder;
|
||||||
// This empty draw rect will not actually be inserted into the stream,
|
// This empty draw rect will not actually be inserted into the stream,
|
||||||
// but the Src blend mode will be synchronized as an attribute. The
|
// but the Src blend mode will be synchronized as an attribute. The
|
||||||
// saveLayer following it should not use that attribute to base its
|
// SaveLayer following it should not use that attribute to base its
|
||||||
// decisions about group opacity and the draw rect after that comes
|
// decisions about group opacity and the draw rect after that comes
|
||||||
// with its own compatible blend mode.
|
// with its own compatible blend mode.
|
||||||
builder.DrawRect(SkRect{0, 0, 0, 0},
|
builder.DrawRect(SkRect{0, 0, 0, 0},
|
||||||
@ -1416,7 +1416,7 @@ TEST_F(DisplayListTest, SaveLayerBoundsSnapshotsImageFilter) {
|
|||||||
DlPaint save_paint;
|
DlPaint save_paint;
|
||||||
builder.SaveLayer(nullptr, &save_paint);
|
builder.SaveLayer(nullptr, &save_paint);
|
||||||
builder.DrawRect(SkRect{50, 50, 100, 100}, DlPaint());
|
builder.DrawRect(SkRect{50, 50, 100, 100}, DlPaint());
|
||||||
// This image filter should be ignored since it was not set before saveLayer
|
// This image filter should be ignored since it was not set before SaveLayer
|
||||||
// And the rect drawn with it will not contribute any more area to the bounds
|
// And the rect drawn with it will not contribute any more area to the bounds
|
||||||
DlPaint draw_paint;
|
DlPaint draw_paint;
|
||||||
draw_paint.setImageFilter(&kTestBlurImageFilter1);
|
draw_paint.setImageFilter(&kTestBlurImageFilter1);
|
||||||
@ -2510,7 +2510,7 @@ TEST_F(DisplayListTest, RTreeOfSaveLayerFilterScene) {
|
|||||||
builder.DrawRect(SkRect{10, 10, 20, 20}, default_paint);
|
builder.DrawRect(SkRect{10, 10, 20, 20}, default_paint);
|
||||||
builder.SaveLayer(nullptr, &filter_paint);
|
builder.SaveLayer(nullptr, &filter_paint);
|
||||||
// the following rectangle will be expanded to 50,50,60,60
|
// the following rectangle will be expanded to 50,50,60,60
|
||||||
// by the saveLayer filter during the restore operation
|
// by the SaveLayer filter during the restore operation
|
||||||
builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint);
|
builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint);
|
||||||
builder.Restore();
|
builder.Restore();
|
||||||
auto display_list = builder.Build();
|
auto display_list = builder.Build();
|
||||||
@ -3272,7 +3272,7 @@ TEST_F(DisplayListTest, RTreeOfClippedSaveLayerFilterScene) {
|
|||||||
builder.ClipRect(SkRect{50, 50, 60, 60}, ClipOp::kIntersect, false);
|
builder.ClipRect(SkRect{50, 50, 60, 60}, ClipOp::kIntersect, false);
|
||||||
builder.SaveLayer(nullptr, &filter_paint);
|
builder.SaveLayer(nullptr, &filter_paint);
|
||||||
// the following rectangle will be expanded to 23,23,87,87
|
// the following rectangle will be expanded to 23,23,87,87
|
||||||
// by the saveLayer filter during the restore operation
|
// by the SaveLayer filter during the restore operation
|
||||||
// but it will then be clipped to 50,50,60,60
|
// but it will then be clipped to 50,50,60,60
|
||||||
builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint);
|
builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint);
|
||||||
builder.Restore();
|
builder.Restore();
|
||||||
@ -3862,7 +3862,7 @@ TEST_F(DisplayListTest, TransformResetSaveLayerBoundsComputationOfSimpleRect) {
|
|||||||
builder.SaveLayer(nullptr, nullptr);
|
builder.SaveLayer(nullptr, nullptr);
|
||||||
builder.TransformReset();
|
builder.TransformReset();
|
||||||
builder.Scale(20.0f, 20.0f);
|
builder.Scale(20.0f, 20.0f);
|
||||||
// Net local transform for saveLayer is Scale(2, 2)
|
// Net local transform for SaveLayer is Scale(2, 2)
|
||||||
{ //
|
{ //
|
||||||
builder.DrawRect(rect, DlPaint());
|
builder.DrawRect(rect, DlPaint());
|
||||||
}
|
}
|
||||||
@ -4451,7 +4451,7 @@ TEST_F(DisplayListTest, MaxBlendModeInsideComplexSaveLayers) {
|
|||||||
builder.Restore();
|
builder.Restore();
|
||||||
|
|
||||||
// Double check that kModulate is the max blend mode for the first
|
// Double check that kModulate is the max blend mode for the first
|
||||||
// saveLayer operations
|
// SaveLayer operations
|
||||||
auto expect = std::max(DlBlendMode::kModulate, DlBlendMode::kSrc);
|
auto expect = std::max(DlBlendMode::kModulate, DlBlendMode::kSrc);
|
||||||
ASSERT_EQ(expect, DlBlendMode::kModulate);
|
ASSERT_EQ(expect, DlBlendMode::kModulate);
|
||||||
|
|
||||||
@ -4487,8 +4487,8 @@ TEST_F(DisplayListTest, BackdropDetectionSimpleSaveLayer) {
|
|||||||
auto dl = builder.Build();
|
auto dl = builder.Build();
|
||||||
|
|
||||||
EXPECT_TRUE(dl->root_has_backdrop_filter());
|
EXPECT_TRUE(dl->root_has_backdrop_filter());
|
||||||
// The saveLayer itself, though, does not have the contains backdrop
|
// The SaveLayer itself, though, does not have the contains backdrop
|
||||||
// flag set because its content does not contain a saveLayer with backdrop
|
// flag set because its content does not contain a SaveLayer with backdrop
|
||||||
SAVE_LAYER_EXPECTOR(expector);
|
SAVE_LAYER_EXPECTOR(expector);
|
||||||
expector.addExpectation(
|
expector.addExpectation(
|
||||||
SaveLayerOptions::kNoAttributes.with_can_distribute_opacity());
|
SaveLayerOptions::kNoAttributes.with_can_distribute_opacity());
|
||||||
@ -5948,5 +5948,132 @@ TEST_F(DisplayListTest, RecordSingleLargeDisplayListOperation) {
|
|||||||
EXPECT_TRUE(!!builder.Build());
|
EXPECT_TRUE(!!builder.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DisplayListTest, DisplayListDetectsRuntimeEffect) {
|
||||||
|
const auto runtime_effect = DlRuntimeEffect::MakeSkia(
|
||||||
|
SkRuntimeEffect::MakeForShader(
|
||||||
|
SkString("vec4 main(vec2 p) { return vec4(0); }"))
|
||||||
|
.effect);
|
||||||
|
auto color_source = DlColorSource::MakeRuntimeEffect(
|
||||||
|
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
|
||||||
|
auto image_filter = DlImageFilter::MakeRuntimeEffect(
|
||||||
|
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
|
||||||
|
|
||||||
|
{
|
||||||
|
// Default - no runtime effects, supports group opacity
|
||||||
|
DisplayListBuilder builder;
|
||||||
|
DlPaint paint;
|
||||||
|
|
||||||
|
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
|
||||||
|
EXPECT_TRUE(builder.Build()->can_apply_group_opacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw with RTE color source does not support group opacity
|
||||||
|
DisplayListBuilder builder;
|
||||||
|
DlPaint paint;
|
||||||
|
|
||||||
|
paint.setColorSource(color_source);
|
||||||
|
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
|
||||||
|
|
||||||
|
EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw with RTE image filter does not support group opacity
|
||||||
|
DisplayListBuilder builder;
|
||||||
|
DlPaint paint;
|
||||||
|
|
||||||
|
paint.setImageFilter(image_filter);
|
||||||
|
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
|
||||||
|
|
||||||
|
EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw with RTE color source inside SaveLayer does not support group
|
||||||
|
// opacity on the SaveLayer, but does support it on the DisplayList
|
||||||
|
DisplayListBuilder builder;
|
||||||
|
DlPaint paint;
|
||||||
|
|
||||||
|
builder.SaveLayer(nullptr, nullptr);
|
||||||
|
paint.setColorSource(color_source);
|
||||||
|
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
|
||||||
|
builder.Restore();
|
||||||
|
|
||||||
|
auto display_list = builder.Build();
|
||||||
|
EXPECT_TRUE(display_list->can_apply_group_opacity());
|
||||||
|
|
||||||
|
SAVE_LAYER_EXPECTOR(expector);
|
||||||
|
expector.addExpectation([](const SaveLayerOptions& options) {
|
||||||
|
return !options.can_distribute_opacity();
|
||||||
|
});
|
||||||
|
display_list->Dispatch(expector);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw with RTE image filter inside SaveLayer does not support group
|
||||||
|
// opacity on the SaveLayer, but does support it on the DisplayList
|
||||||
|
DisplayListBuilder builder;
|
||||||
|
DlPaint paint;
|
||||||
|
|
||||||
|
builder.SaveLayer(nullptr, nullptr);
|
||||||
|
paint.setImageFilter(image_filter);
|
||||||
|
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
|
||||||
|
builder.Restore();
|
||||||
|
|
||||||
|
auto display_list = builder.Build();
|
||||||
|
EXPECT_TRUE(display_list->can_apply_group_opacity());
|
||||||
|
|
||||||
|
SAVE_LAYER_EXPECTOR(expector);
|
||||||
|
expector.addExpectation([](const SaveLayerOptions& options) {
|
||||||
|
return !options.can_distribute_opacity();
|
||||||
|
});
|
||||||
|
display_list->Dispatch(expector);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw with RTE color source inside nested saveLayers does not support
|
||||||
|
// group opacity on the inner SaveLayer, but does support it on the
|
||||||
|
// outer SaveLayer and the DisplayList
|
||||||
|
DisplayListBuilder builder;
|
||||||
|
DlPaint paint;
|
||||||
|
|
||||||
|
builder.SaveLayer(nullptr, nullptr);
|
||||||
|
|
||||||
|
builder.SaveLayer(nullptr, nullptr);
|
||||||
|
paint.setColorSource(color_source);
|
||||||
|
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
|
||||||
|
paint.setColorSource(nullptr);
|
||||||
|
builder.Restore();
|
||||||
|
|
||||||
|
builder.SaveLayer(nullptr, nullptr);
|
||||||
|
paint.setImageFilter(image_filter);
|
||||||
|
// Make sure these DrawRects are non-overlapping otherwise the outer
|
||||||
|
// SaveLayer and DisplayList will be incompatible due to overlaps
|
||||||
|
builder.DrawRect(DlRect::MakeLTRB(60, 60, 100, 100), paint);
|
||||||
|
paint.setImageFilter(nullptr);
|
||||||
|
builder.Restore();
|
||||||
|
|
||||||
|
builder.Restore();
|
||||||
|
auto display_list = builder.Build();
|
||||||
|
EXPECT_TRUE(display_list->can_apply_group_opacity());
|
||||||
|
|
||||||
|
SAVE_LAYER_EXPECTOR(expector);
|
||||||
|
expector.addExpectation([](const SaveLayerOptions& options) {
|
||||||
|
// outer SaveLayer supports group opacity
|
||||||
|
return options.can_distribute_opacity();
|
||||||
|
});
|
||||||
|
expector.addExpectation([](const SaveLayerOptions& options) {
|
||||||
|
// first inner SaveLayer does not support group opacity
|
||||||
|
return !options.can_distribute_opacity();
|
||||||
|
});
|
||||||
|
expector.addExpectation([](const SaveLayerOptions& options) {
|
||||||
|
// second inner SaveLayer does not support group opacity
|
||||||
|
return !options.can_distribute_opacity();
|
||||||
|
});
|
||||||
|
display_list->Dispatch(expector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
} // namespace flutter
|
} // namespace flutter
|
||||||
|
@ -244,6 +244,7 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UpdateCurrentOpacityCompatibility();
|
||||||
}
|
}
|
||||||
void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
|
void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
|
||||||
if (filter == nullptr) {
|
if (filter == nullptr) {
|
||||||
@ -289,6 +290,7 @@ void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UpdateCurrentOpacityCompatibility();
|
||||||
}
|
}
|
||||||
void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) {
|
void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) {
|
||||||
if (filter == nullptr) {
|
if (filter == nullptr) {
|
||||||
|
@ -723,6 +723,7 @@ class DisplayListBuilder final : public virtual DlCanvas,
|
|||||||
current_opacity_compatibility_ = //
|
current_opacity_compatibility_ = //
|
||||||
current_.getColorFilter() == nullptr && //
|
current_.getColorFilter() == nullptr && //
|
||||||
!current_.isInvertColors() && //
|
!current_.isInvertColors() && //
|
||||||
|
!current_.usesRuntimeEffect() && //
|
||||||
IsOpacityCompatible(current_.getBlendMode());
|
IsOpacityCompatible(current_.getBlendMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +178,11 @@ class DlPaint {
|
|||||||
|
|
||||||
bool isDefault() const { return *this == kDefault; }
|
bool isDefault() const { return *this == kDefault; }
|
||||||
|
|
||||||
|
bool usesRuntimeEffect() const {
|
||||||
|
return ((color_source_ && color_source_->asRuntimeEffect()) ||
|
||||||
|
(image_filter_ && image_filter_->asRuntimeEffectFilter()));
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(DlPaint const& other) const;
|
bool operator==(DlPaint const& other) const;
|
||||||
bool operator!=(DlPaint const& other) const { return !(*this == other); }
|
bool operator!=(DlPaint const& other) const { return !(*this == other); }
|
||||||
|
|
||||||
|
@ -154,5 +154,49 @@ TEST(DisplayListPaint, ChainingConstructor) {
|
|||||||
EXPECT_NE(paint, DlPaint());
|
EXPECT_NE(paint, DlPaint());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DisplayListPaint, PaintDetectsRuntimeEffects) {
|
||||||
|
const auto runtime_effect = DlRuntimeEffect::MakeSkia(
|
||||||
|
SkRuntimeEffect::MakeForShader(
|
||||||
|
SkString("vec4 main(vec2 p) { return vec4(0); }"))
|
||||||
|
.effect);
|
||||||
|
auto color_source = DlColorSource::MakeRuntimeEffect(
|
||||||
|
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
|
||||||
|
auto image_filter = DlImageFilter::MakeRuntimeEffect(
|
||||||
|
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
|
||||||
|
DlPaint paint;
|
||||||
|
|
||||||
|
EXPECT_FALSE(paint.usesRuntimeEffect());
|
||||||
|
paint.setColorSource(color_source);
|
||||||
|
EXPECT_TRUE(paint.usesRuntimeEffect());
|
||||||
|
paint.setColorSource(nullptr);
|
||||||
|
EXPECT_FALSE(paint.usesRuntimeEffect());
|
||||||
|
|
||||||
|
EXPECT_FALSE(paint.usesRuntimeEffect());
|
||||||
|
paint.setImageFilter(image_filter);
|
||||||
|
EXPECT_TRUE(paint.usesRuntimeEffect());
|
||||||
|
paint.setImageFilter(nullptr);
|
||||||
|
EXPECT_FALSE(paint.usesRuntimeEffect());
|
||||||
|
|
||||||
|
EXPECT_FALSE(paint.usesRuntimeEffect());
|
||||||
|
paint.setColorSource(color_source);
|
||||||
|
EXPECT_TRUE(paint.usesRuntimeEffect());
|
||||||
|
paint.setImageFilter(image_filter);
|
||||||
|
EXPECT_TRUE(paint.usesRuntimeEffect());
|
||||||
|
paint.setImageFilter(nullptr);
|
||||||
|
EXPECT_TRUE(paint.usesRuntimeEffect());
|
||||||
|
paint.setColorSource(nullptr);
|
||||||
|
EXPECT_FALSE(paint.usesRuntimeEffect());
|
||||||
|
|
||||||
|
EXPECT_FALSE(paint.usesRuntimeEffect());
|
||||||
|
paint.setColorSource(color_source);
|
||||||
|
EXPECT_TRUE(paint.usesRuntimeEffect());
|
||||||
|
paint.setImageFilter(image_filter);
|
||||||
|
EXPECT_TRUE(paint.usesRuntimeEffect());
|
||||||
|
paint.setColorSource(nullptr);
|
||||||
|
EXPECT_TRUE(paint.usesRuntimeEffect());
|
||||||
|
paint.setImageFilter(nullptr);
|
||||||
|
EXPECT_FALSE(paint.usesRuntimeEffect());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
} // namespace flutter
|
} // namespace flutter
|
||||||
|
Loading…
x
Reference in New Issue
Block a user