Skip to content

Commit 1c2cd45

Browse files
authored
[DisplayList] Disable group opacity when a RuntimeEffect is in use (flutter/engine#56936)
Fixes flutter#158500 Impeller does not support group opacity for RuntimeEffects so we disable the optimization with a flag when it is detected.
1 parent 72d1c2f commit 1c2cd45

File tree

5 files changed

+187
-8
lines changed

5 files changed

+187
-8
lines changed

engine/src/flutter/display_list/display_list_unittests.cc

+135-8
Original file line numberDiff line numberDiff line change
@@ -1367,7 +1367,7 @@ TEST_F(DisplayListTest, SaveLayerFalseWithSrcBlendSupportsGroupOpacity) {
13671367
DisplayListBuilder builder;
13681368
// This empty draw rect will not actually be inserted into the stream,
13691369
// but the Src blend mode will be synchronized as an attribute. The
1370-
// saveLayer following it should not use that attribute to base its
1370+
// SaveLayer following it should not use that attribute to base its
13711371
// decisions about group opacity and the draw rect after that comes
13721372
// with its own compatible blend mode.
13731373
builder.DrawRect(SkRect{0, 0, 0, 0},
@@ -1416,7 +1416,7 @@ TEST_F(DisplayListTest, SaveLayerBoundsSnapshotsImageFilter) {
14161416
DlPaint save_paint;
14171417
builder.SaveLayer(nullptr, &save_paint);
14181418
builder.DrawRect(SkRect{50, 50, 100, 100}, DlPaint());
1419-
// This image filter should be ignored since it was not set before saveLayer
1419+
// This image filter should be ignored since it was not set before SaveLayer
14201420
// And the rect drawn with it will not contribute any more area to the bounds
14211421
DlPaint draw_paint;
14221422
draw_paint.setImageFilter(&kTestBlurImageFilter1);
@@ -2510,7 +2510,7 @@ TEST_F(DisplayListTest, RTreeOfSaveLayerFilterScene) {
25102510
builder.DrawRect(SkRect{10, 10, 20, 20}, default_paint);
25112511
builder.SaveLayer(nullptr, &filter_paint);
25122512
// the following rectangle will be expanded to 50,50,60,60
2513-
// by the saveLayer filter during the restore operation
2513+
// by the SaveLayer filter during the restore operation
25142514
builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint);
25152515
builder.Restore();
25162516
auto display_list = builder.Build();
@@ -3272,7 +3272,7 @@ TEST_F(DisplayListTest, RTreeOfClippedSaveLayerFilterScene) {
32723272
builder.ClipRect(SkRect{50, 50, 60, 60}, ClipOp::kIntersect, false);
32733273
builder.SaveLayer(nullptr, &filter_paint);
32743274
// the following rectangle will be expanded to 23,23,87,87
3275-
// by the saveLayer filter during the restore operation
3275+
// by the SaveLayer filter during the restore operation
32763276
// but it will then be clipped to 50,50,60,60
32773277
builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint);
32783278
builder.Restore();
@@ -3862,7 +3862,7 @@ TEST_F(DisplayListTest, TransformResetSaveLayerBoundsComputationOfSimpleRect) {
38623862
builder.SaveLayer(nullptr, nullptr);
38633863
builder.TransformReset();
38643864
builder.Scale(20.0f, 20.0f);
3865-
// Net local transform for saveLayer is Scale(2, 2)
3865+
// Net local transform for SaveLayer is Scale(2, 2)
38663866
{ //
38673867
builder.DrawRect(rect, DlPaint());
38683868
}
@@ -4451,7 +4451,7 @@ TEST_F(DisplayListTest, MaxBlendModeInsideComplexSaveLayers) {
44514451
builder.Restore();
44524452

44534453
// Double check that kModulate is the max blend mode for the first
4454-
// saveLayer operations
4454+
// SaveLayer operations
44554455
auto expect = std::max(DlBlendMode::kModulate, DlBlendMode::kSrc);
44564456
ASSERT_EQ(expect, DlBlendMode::kModulate);
44574457

@@ -4487,8 +4487,8 @@ TEST_F(DisplayListTest, BackdropDetectionSimpleSaveLayer) {
44874487
auto dl = builder.Build();
44884488

44894489
EXPECT_TRUE(dl->root_has_backdrop_filter());
4490-
// The saveLayer itself, though, does not have the contains backdrop
4491-
// flag set because its content does not contain a saveLayer with backdrop
4490+
// The SaveLayer itself, though, does not have the contains backdrop
4491+
// flag set because its content does not contain a SaveLayer with backdrop
44924492
SAVE_LAYER_EXPECTOR(expector);
44934493
expector.addExpectation(
44944494
SaveLayerOptions::kNoAttributes.with_can_distribute_opacity());
@@ -5948,5 +5948,132 @@ TEST_F(DisplayListTest, RecordSingleLargeDisplayListOperation) {
59485948
EXPECT_TRUE(!!builder.Build());
59495949
}
59505950

5951+
TEST_F(DisplayListTest, DisplayListDetectsRuntimeEffect) {
5952+
const auto runtime_effect = DlRuntimeEffect::MakeSkia(
5953+
SkRuntimeEffect::MakeForShader(
5954+
SkString("vec4 main(vec2 p) { return vec4(0); }"))
5955+
.effect);
5956+
auto color_source = DlColorSource::MakeRuntimeEffect(
5957+
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
5958+
auto image_filter = DlImageFilter::MakeRuntimeEffect(
5959+
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
5960+
5961+
{
5962+
// Default - no runtime effects, supports group opacity
5963+
DisplayListBuilder builder;
5964+
DlPaint paint;
5965+
5966+
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
5967+
EXPECT_TRUE(builder.Build()->can_apply_group_opacity());
5968+
}
5969+
5970+
{
5971+
// Draw with RTE color source does not support group opacity
5972+
DisplayListBuilder builder;
5973+
DlPaint paint;
5974+
5975+
paint.setColorSource(color_source);
5976+
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
5977+
5978+
EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
5979+
}
5980+
5981+
{
5982+
// Draw with RTE image filter does not support group opacity
5983+
DisplayListBuilder builder;
5984+
DlPaint paint;
5985+
5986+
paint.setImageFilter(image_filter);
5987+
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
5988+
5989+
EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
5990+
}
5991+
5992+
{
5993+
// Draw with RTE color source inside SaveLayer does not support group
5994+
// opacity on the SaveLayer, but does support it on the DisplayList
5995+
DisplayListBuilder builder;
5996+
DlPaint paint;
5997+
5998+
builder.SaveLayer(nullptr, nullptr);
5999+
paint.setColorSource(color_source);
6000+
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
6001+
builder.Restore();
6002+
6003+
auto display_list = builder.Build();
6004+
EXPECT_TRUE(display_list->can_apply_group_opacity());
6005+
6006+
SAVE_LAYER_EXPECTOR(expector);
6007+
expector.addExpectation([](const SaveLayerOptions& options) {
6008+
return !options.can_distribute_opacity();
6009+
});
6010+
display_list->Dispatch(expector);
6011+
}
6012+
6013+
{
6014+
// Draw with RTE image filter inside SaveLayer does not support group
6015+
// opacity on the SaveLayer, but does support it on the DisplayList
6016+
DisplayListBuilder builder;
6017+
DlPaint paint;
6018+
6019+
builder.SaveLayer(nullptr, nullptr);
6020+
paint.setImageFilter(image_filter);
6021+
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
6022+
builder.Restore();
6023+
6024+
auto display_list = builder.Build();
6025+
EXPECT_TRUE(display_list->can_apply_group_opacity());
6026+
6027+
SAVE_LAYER_EXPECTOR(expector);
6028+
expector.addExpectation([](const SaveLayerOptions& options) {
6029+
return !options.can_distribute_opacity();
6030+
});
6031+
display_list->Dispatch(expector);
6032+
}
6033+
6034+
{
6035+
// Draw with RTE color source inside nested saveLayers does not support
6036+
// group opacity on the inner SaveLayer, but does support it on the
6037+
// outer SaveLayer and the DisplayList
6038+
DisplayListBuilder builder;
6039+
DlPaint paint;
6040+
6041+
builder.SaveLayer(nullptr, nullptr);
6042+
6043+
builder.SaveLayer(nullptr, nullptr);
6044+
paint.setColorSource(color_source);
6045+
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
6046+
paint.setColorSource(nullptr);
6047+
builder.Restore();
6048+
6049+
builder.SaveLayer(nullptr, nullptr);
6050+
paint.setImageFilter(image_filter);
6051+
// Make sure these DrawRects are non-overlapping otherwise the outer
6052+
// SaveLayer and DisplayList will be incompatible due to overlaps
6053+
builder.DrawRect(DlRect::MakeLTRB(60, 60, 100, 100), paint);
6054+
paint.setImageFilter(nullptr);
6055+
builder.Restore();
6056+
6057+
builder.Restore();
6058+
auto display_list = builder.Build();
6059+
EXPECT_TRUE(display_list->can_apply_group_opacity());
6060+
6061+
SAVE_LAYER_EXPECTOR(expector);
6062+
expector.addExpectation([](const SaveLayerOptions& options) {
6063+
// outer SaveLayer supports group opacity
6064+
return options.can_distribute_opacity();
6065+
});
6066+
expector.addExpectation([](const SaveLayerOptions& options) {
6067+
// first inner SaveLayer does not support group opacity
6068+
return !options.can_distribute_opacity();
6069+
});
6070+
expector.addExpectation([](const SaveLayerOptions& options) {
6071+
// second inner SaveLayer does not support group opacity
6072+
return !options.can_distribute_opacity();
6073+
});
6074+
display_list->Dispatch(expector);
6075+
}
6076+
}
6077+
59516078
} // namespace testing
59526079
} // namespace flutter

engine/src/flutter/display_list/dl_builder.cc

+2
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) {
244244
}
245245
}
246246
}
247+
UpdateCurrentOpacityCompatibility();
247248
}
248249
void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
249250
if (filter == nullptr) {
@@ -289,6 +290,7 @@ void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
289290
}
290291
}
291292
}
293+
UpdateCurrentOpacityCompatibility();
292294
}
293295
void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) {
294296
if (filter == nullptr) {

engine/src/flutter/display_list/dl_builder.h

+1
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,7 @@ class DisplayListBuilder final : public virtual DlCanvas,
723723
current_opacity_compatibility_ = //
724724
current_.getColorFilter() == nullptr && //
725725
!current_.isInvertColors() && //
726+
!current_.usesRuntimeEffect() && //
726727
IsOpacityCompatible(current_.getBlendMode());
727728
}
728729

engine/src/flutter/display_list/dl_paint.h

+5
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@ class DlPaint {
178178

179179
bool isDefault() const { return *this == kDefault; }
180180

181+
bool usesRuntimeEffect() const {
182+
return ((color_source_ && color_source_->asRuntimeEffect()) ||
183+
(image_filter_ && image_filter_->asRuntimeEffectFilter()));
184+
}
185+
181186
bool operator==(DlPaint const& other) const;
182187
bool operator!=(DlPaint const& other) const { return !(*this == other); }
183188

engine/src/flutter/display_list/dl_paint_unittests.cc

+44
Original file line numberDiff line numberDiff line change
@@ -154,5 +154,49 @@ TEST(DisplayListPaint, ChainingConstructor) {
154154
EXPECT_NE(paint, DlPaint());
155155
}
156156

157+
TEST(DisplayListPaint, PaintDetectsRuntimeEffects) {
158+
const auto runtime_effect = DlRuntimeEffect::MakeSkia(
159+
SkRuntimeEffect::MakeForShader(
160+
SkString("vec4 main(vec2 p) { return vec4(0); }"))
161+
.effect);
162+
auto color_source = DlColorSource::MakeRuntimeEffect(
163+
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
164+
auto image_filter = DlImageFilter::MakeRuntimeEffect(
165+
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
166+
DlPaint paint;
167+
168+
EXPECT_FALSE(paint.usesRuntimeEffect());
169+
paint.setColorSource(color_source);
170+
EXPECT_TRUE(paint.usesRuntimeEffect());
171+
paint.setColorSource(nullptr);
172+
EXPECT_FALSE(paint.usesRuntimeEffect());
173+
174+
EXPECT_FALSE(paint.usesRuntimeEffect());
175+
paint.setImageFilter(image_filter);
176+
EXPECT_TRUE(paint.usesRuntimeEffect());
177+
paint.setImageFilter(nullptr);
178+
EXPECT_FALSE(paint.usesRuntimeEffect());
179+
180+
EXPECT_FALSE(paint.usesRuntimeEffect());
181+
paint.setColorSource(color_source);
182+
EXPECT_TRUE(paint.usesRuntimeEffect());
183+
paint.setImageFilter(image_filter);
184+
EXPECT_TRUE(paint.usesRuntimeEffect());
185+
paint.setImageFilter(nullptr);
186+
EXPECT_TRUE(paint.usesRuntimeEffect());
187+
paint.setColorSource(nullptr);
188+
EXPECT_FALSE(paint.usesRuntimeEffect());
189+
190+
EXPECT_FALSE(paint.usesRuntimeEffect());
191+
paint.setColorSource(color_source);
192+
EXPECT_TRUE(paint.usesRuntimeEffect());
193+
paint.setImageFilter(image_filter);
194+
EXPECT_TRUE(paint.usesRuntimeEffect());
195+
paint.setColorSource(nullptr);
196+
EXPECT_TRUE(paint.usesRuntimeEffect());
197+
paint.setImageFilter(nullptr);
198+
EXPECT_FALSE(paint.usesRuntimeEffect());
199+
}
200+
157201
} // namespace testing
158202
} // namespace flutter

0 commit comments

Comments
 (0)