[Impeller] Fix accumulating translucency opacity peephole bug (#40639)
diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 420f7f5..21db229 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc
@@ -31,7 +31,7 @@ auto& source = color_source.value(); auto contents = source(); contents->SetGeometry(std::move(geometry)); - contents->SetAlpha(color.alpha); + contents->SetOpacity(color.alpha); return contents; } auto solid_color = std::make_shared<SolidColorContents>(); @@ -46,7 +46,7 @@ auto& source = color_source.value(); auto contents = source(); contents->SetGeometry(geometry); - contents->SetAlpha(color.alpha); + contents->SetOpacity(color.alpha); return contents; } auto solid_color = std::make_shared<SolidColorContents>();
diff --git a/impeller/aiks/paint_pass_delegate.cc b/impeller/aiks/paint_pass_delegate.cc index c308a7f..b1126ce 100644 --- a/impeller/aiks/paint_pass_delegate.cc +++ b/impeller/aiks/paint_pass_delegate.cc
@@ -97,7 +97,7 @@ auto had_subpass = entity_pass->IterateUntilSubpass( [&all_coverages, &all_can_accept](Entity& entity) { auto contents = entity.GetContents(); - if (!contents->CanAcceptOpacity(entity)) { + if (!contents->CanInheritOpacity(entity)) { all_can_accept = false; return false; }
diff --git a/impeller/entity/contents/clip_contents.cc b/impeller/entity/contents/clip_contents.cc index 4a79d00..92085b7 100644 --- a/impeller/entity/contents/clip_contents.cc +++ b/impeller/entity/contents/clip_contents.cc
@@ -70,7 +70,7 @@ return true; } -bool ClipContents::CanAcceptOpacity(const Entity& entity) const { +bool ClipContents::CanInheritOpacity(const Entity& entity) const { return true; } @@ -172,7 +172,7 @@ return true; } -bool ClipRestoreContents::CanAcceptOpacity(const Entity& entity) const { +bool ClipRestoreContents::CanInheritOpacity(const Entity& entity) const { return true; }
diff --git a/impeller/entity/contents/clip_contents.h b/impeller/entity/contents/clip_contents.h index cb08ab4..f75c352 100644 --- a/impeller/entity/contents/clip_contents.h +++ b/impeller/entity/contents/clip_contents.h
@@ -42,7 +42,7 @@ const Entity& entity, RenderPass& pass) const override; // |Contents| - bool CanAcceptOpacity(const Entity& entity) const override; + bool CanInheritOpacity(const Entity& entity) const override; // |Contents| void SetInheritedOpacity(Scalar opacity) override; @@ -84,7 +84,7 @@ RenderPass& pass) const override; // |Contents| - bool CanAcceptOpacity(const Entity& entity) const override; + bool CanInheritOpacity(const Entity& entity) const override; // |Contents| void SetInheritedOpacity(Scalar opacity) override;
diff --git a/impeller/entity/contents/color_source_contents.cc b/impeller/entity/contents/color_source_contents.cc index 2c68974..4eef31d 100644 --- a/impeller/entity/contents/color_source_contents.cc +++ b/impeller/entity/contents/color_source_contents.cc
@@ -21,12 +21,12 @@ return geometry_; } -void ColorSourceContents::SetAlpha(Scalar alpha) { - alpha_ = alpha; +void ColorSourceContents::SetOpacity(Scalar alpha) { + opacity_ = alpha; } -Scalar ColorSourceContents::GetAlpha() const { - return alpha_; +Scalar ColorSourceContents::GetOpacity() const { + return opacity_ * inherited_opacity_; } void ColorSourceContents::SetEffectTransform(Matrix matrix) { @@ -42,12 +42,12 @@ return geometry_->GetCoverage(entity.GetTransformation()); }; -bool ColorSourceContents::CanAcceptOpacity(const Entity& entity) const { +bool ColorSourceContents::CanInheritOpacity(const Entity& entity) const { return true; } void ColorSourceContents::SetInheritedOpacity(Scalar opacity) { - SetAlpha(GetAlpha() * opacity); + inherited_opacity_ = opacity; } bool ColorSourceContents::ShouldRender(
diff --git a/impeller/entity/contents/color_source_contents.h b/impeller/entity/contents/color_source_contents.h index 0129aa5..b13d2d9 100644 --- a/impeller/entity/contents/color_source_contents.h +++ b/impeller/entity/contents/color_source_contents.h
@@ -24,7 +24,7 @@ const Matrix& GetInverseMatrix() const; - void SetAlpha(Scalar alpha); + void SetOpacity(Scalar opacity); // |Contents| std::optional<Rect> GetCoverage(const Entity& entity) const override; @@ -33,13 +33,13 @@ bool ShouldRender(const Entity& entity, const std::optional<Rect>& stencil_coverage) const override; - // | Contents| - bool CanAcceptOpacity(const Entity& entity) const override; + // |Contents| + bool CanInheritOpacity(const Entity& entity) const override; - // | Contents| + // |Contents| void SetInheritedOpacity(Scalar opacity) override; - Scalar GetAlpha() const; + Scalar GetOpacity() const; protected: const std::shared_ptr<Geometry>& GetGeometry() const; @@ -47,7 +47,8 @@ private: std::shared_ptr<Geometry> geometry_; Matrix inverse_matrix_; - Scalar alpha_ = 1.0; + Scalar opacity_ = 1.0; + Scalar inherited_opacity_ = 1.0; FML_DISALLOW_COPY_AND_ASSIGN(ColorSourceContents); };
diff --git a/impeller/entity/contents/conical_gradient_contents.cc b/impeller/entity/contents/conical_gradient_contents.cc index 4ff50cb..37d3484 100644 --- a/impeller/entity/contents/conical_gradient_contents.cc +++ b/impeller/entity/contents/conical_gradient_contents.cc
@@ -70,7 +70,7 @@ frag_info.center = center_; frag_info.radius = radius_; frag_info.tile_mode = static_cast<Scalar>(tile_mode_); - frag_info.alpha = GetAlpha(); + frag_info.alpha = GetOpacity(); if (focus_) { frag_info.focus = focus_.value(); frag_info.focus_radius = focus_radius_; @@ -141,7 +141,7 @@ frag_info.radius = radius_; frag_info.tile_mode = static_cast<Scalar>(tile_mode_); frag_info.texture_sampler_y_coord_scale = gradient_texture->GetYCoordScale(); - frag_info.alpha = GetAlpha(); + frag_info.alpha = GetOpacity(); frag_info.half_texel = Vector2(0.5 / gradient_texture->GetSize().width, 0.5 / gradient_texture->GetSize().height); if (focus_) {
diff --git a/impeller/entity/contents/contents.cc b/impeller/entity/contents/contents.cc index fc7e989..58377c4 100644 --- a/impeller/entity/contents/contents.cc +++ b/impeller/entity/contents/contents.cc
@@ -95,7 +95,7 @@ return snapshot; } -bool Contents::CanAcceptOpacity(const Entity& entity) const { +bool Contents::CanInheritOpacity(const Entity& entity) const { return false; }
diff --git a/impeller/entity/contents/contents.h b/impeller/entity/contents/contents.h index 85ac87b..c598b3c 100644 --- a/impeller/entity/contents/contents.h +++ b/impeller/entity/contents/contents.h
@@ -94,7 +94,7 @@ /// a way that makes accepting opacity impossible. It is always safe /// to return false, especially if computing overlap would be /// computationally expensive. - virtual bool CanAcceptOpacity(const Entity& entity) const; + virtual bool CanInheritOpacity(const Entity& entity) const; /// @brief Inherit the provided opacity. ///
diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index caf9ad6..2fe2e48 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc
@@ -71,7 +71,7 @@ frag_info.end_point = end_point_; frag_info.tile_mode = static_cast<Scalar>(tile_mode_); frag_info.texture_sampler_y_coord_scale = gradient_texture->GetYCoordScale(); - frag_info.alpha = GetAlpha(); + frag_info.alpha = GetOpacity(); frag_info.half_texel = Vector2(0.5 / gradient_texture->GetSize().width, 0.5 / gradient_texture->GetSize().height); @@ -126,7 +126,7 @@ frag_info.start_point = start_point_; frag_info.end_point = end_point_; frag_info.tile_mode = static_cast<Scalar>(tile_mode_); - frag_info.alpha = GetAlpha(); + frag_info.alpha = GetOpacity(); auto& host_buffer = pass.GetTransientsBuffer(); auto colors = CreateGradientColors(colors_, stops_);
diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index 44f10bc..76d989f 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc
@@ -64,7 +64,7 @@ frag_info.center = center_; frag_info.radius = radius_; frag_info.tile_mode = static_cast<Scalar>(tile_mode_); - frag_info.alpha = GetAlpha(); + frag_info.alpha = GetOpacity(); auto& host_buffer = pass.GetTransientsBuffer(); auto colors = CreateGradientColors(colors_, stops_); @@ -128,7 +128,7 @@ frag_info.radius = radius_; frag_info.tile_mode = static_cast<Scalar>(tile_mode_); frag_info.texture_sampler_y_coord_scale = gradient_texture->GetYCoordScale(); - frag_info.alpha = GetAlpha(); + frag_info.alpha = GetOpacity(); frag_info.half_texel = Vector2(0.5 / gradient_texture->GetSize().width, 0.5 / gradient_texture->GetSize().height);
diff --git a/impeller/entity/contents/runtime_effect_contents.cc b/impeller/entity/contents/runtime_effect_contents.cc index 7cfd53d..0ac8fbd 100644 --- a/impeller/entity/contents/runtime_effect_contents.cc +++ b/impeller/entity/contents/runtime_effect_contents.cc
@@ -37,7 +37,7 @@ texture_inputs_ = std::move(texture_inputs); } -bool RuntimeEffectContents::CanAcceptOpacity(const Entity& entity) const { +bool RuntimeEffectContents::CanInheritOpacity(const Entity& entity) const { return false; }
diff --git a/impeller/entity/contents/runtime_effect_contents.h b/impeller/entity/contents/runtime_effect_contents.h index 725aadf..a1baab4 100644 --- a/impeller/entity/contents/runtime_effect_contents.h +++ b/impeller/entity/contents/runtime_effect_contents.h
@@ -26,7 +26,7 @@ void SetTextureInputs(std::vector<TextureInput> texture_inputs); // | Contents| - bool CanAcceptOpacity(const Entity& entity) const override; + bool CanInheritOpacity(const Entity& entity) const override; // |Contents| bool Render(const ContentContext& renderer,
diff --git a/impeller/entity/contents/solid_color_contents.cc b/impeller/entity/contents/solid_color_contents.cc index 09e9210..28c5145 100644 --- a/impeller/entity/contents/solid_color_contents.cc +++ b/impeller/entity/contents/solid_color_contents.cc
@@ -20,8 +20,8 @@ color_ = color; } -const Color& SolidColorContents::GetColor() const { - return color_; +Color SolidColorContents::GetColor() const { + return color_.WithAlpha(color_.alpha * inherited_opacity_); } void SolidColorContents::SetGeometry(std::shared_ptr<Geometry> geometry) { @@ -29,19 +29,18 @@ } // | Contents| -bool SolidColorContents::CanAcceptOpacity(const Entity& entity) const { +bool SolidColorContents::CanInheritOpacity(const Entity& entity) const { return true; } // | Contents| void SolidColorContents::SetInheritedOpacity(Scalar opacity) { - auto color = color_; - color_ = color.WithAlpha(color.alpha * opacity); + inherited_opacity_ = opacity; } std::optional<Rect> SolidColorContents::GetCoverage( const Entity& entity) const { - if (color_.IsTransparent()) { + if (GetColor().IsTransparent()) { return std::nullopt; } if (geometry_ == nullptr) { @@ -86,7 +85,7 @@ VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); FS::FragInfo frag_info; - frag_info.color = color_.Premultiply(); + frag_info.color = GetColor().Premultiply(); FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info)); if (!pass.AddCommand(std::move(cmd))) {
diff --git a/impeller/entity/contents/solid_color_contents.h b/impeller/entity/contents/solid_color_contents.h index 2d57efc..91d5720 100644 --- a/impeller/entity/contents/solid_color_contents.h +++ b/impeller/entity/contents/solid_color_contents.h
@@ -33,10 +33,10 @@ void SetColor(Color color); - const Color& GetColor() const; + Color GetColor() const; // | Contents| - bool CanAcceptOpacity(const Entity& entity) const override; + bool CanInheritOpacity(const Entity& entity) const override; // | Contents| void SetInheritedOpacity(Scalar opacity) override; @@ -57,6 +57,7 @@ std::shared_ptr<Geometry> geometry_; Color color_; + Scalar inherited_opacity_ = 1.0; FML_DISALLOW_COPY_AND_ASSIGN(SolidColorContents); };
diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index 2c10aa6..3ea26e3 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc
@@ -70,7 +70,7 @@ frag_info.bias = bias_; frag_info.scale = scale_; frag_info.tile_mode = static_cast<Scalar>(tile_mode_); - frag_info.alpha = GetAlpha(); + frag_info.alpha = GetOpacity(); auto& host_buffer = pass.GetTransientsBuffer(); auto colors = CreateGradientColors(colors_, stops_); @@ -135,7 +135,7 @@ frag_info.scale = scale_; frag_info.texture_sampler_y_coord_scale = gradient_texture->GetYCoordScale(); frag_info.tile_mode = static_cast<Scalar>(tile_mode_); - frag_info.alpha = GetAlpha(); + frag_info.alpha = GetOpacity(); frag_info.half_texel = Vector2(0.5 / gradient_texture->GetSize().width, 0.5 / gradient_texture->GetSize().height);
diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index 5d420db..42cc718 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc
@@ -51,16 +51,15 @@ } Color TextContents::GetColor() const { - return color_; + return color_.WithAlpha(color_.alpha * inherited_opacity_); } -bool TextContents::CanAcceptOpacity(const Entity& entity) const { +bool TextContents::CanInheritOpacity(const Entity& entity) const { return !frame_.MaybeHasOverlapping(); } void TextContents::SetInheritedOpacity(Scalar opacity) { - auto color = color_; - color_ = color.WithAlpha(color.alpha * opacity); + inherited_opacity_ = opacity; } void TextContents::SetInverseMatrix(Matrix matrix) { @@ -230,13 +229,14 @@ cmd.stencil_reference = entity.GetStencilDepth(); return CommonRender<GlyphAtlasSdfPipeline>( - renderer, entity, pass, color_, frame_, inverse_matrix_, atlas, cmd); + renderer, entity, pass, GetColor(), frame_, inverse_matrix_, atlas, cmd); } bool TextContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - if (color_.IsTransparent()) { + auto color = GetColor(); + if (color.IsTransparent()) { return true; } @@ -264,8 +264,8 @@ cmd.pipeline = renderer.GetGlyphAtlasPipeline(opts); cmd.stencil_reference = entity.GetStencilDepth(); - return CommonRender<GlyphAtlasPipeline>(renderer, entity, pass, color_, - frame_, inverse_matrix_, atlas, cmd); + return CommonRender<GlyphAtlasPipeline>(renderer, entity, pass, color, frame_, + inverse_matrix_, atlas, cmd); } } // namespace impeller
diff --git a/impeller/entity/contents/text_contents.h b/impeller/entity/contents/text_contents.h index d494d48..b36cc83 100644 --- a/impeller/entity/contents/text_contents.h +++ b/impeller/entity/contents/text_contents.h
@@ -34,7 +34,7 @@ Color GetColor() const; - bool CanAcceptOpacity(const Entity& entity) const override; + bool CanInheritOpacity(const Entity& entity) const override; void SetInheritedOpacity(Scalar opacity) override; @@ -56,6 +56,7 @@ private: TextFrame frame_; Color color_; + Scalar inherited_opacity_; mutable std::shared_ptr<LazyGlyphAtlas> lazy_atlas_; Matrix inverse_matrix_;
diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc index 6bfea05..efa7a20 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc
@@ -54,20 +54,20 @@ stencil_enabled_ = enabled; } -bool TextureContents::CanAcceptOpacity(const Entity& entity) const { +bool TextureContents::CanInheritOpacity(const Entity& entity) const { return true; } void TextureContents::SetInheritedOpacity(Scalar opacity) { - opacity_ = opacity_ * opacity; + inherited_opacity_ = opacity; } Scalar TextureContents::GetOpacity() const { - return opacity_; + return opacity_ * inherited_opacity_; } std::optional<Rect> TextureContents::GetCoverage(const Entity& entity) const { - if (opacity_ == 0) { + if (GetOpacity() == 0) { return std::nullopt; } return rect_.TransformBounds(entity.GetTransformation()); @@ -81,8 +81,9 @@ // Passthrough textures that have simple rectangle paths and complete source // rects. auto bounds = rect_; + auto opacity = GetOpacity(); if (source_rect_ == Rect::MakeSize(texture_->GetSize()) && - (opacity_ >= 1 - kEhCloseEnough || defer_applying_opacity_)) { + (opacity >= 1 - kEhCloseEnough || defer_applying_opacity_)) { auto scale = Vector2(bounds.size / Size(texture_->GetSize())); return Snapshot{ .texture = texture_, @@ -90,7 +91,7 @@ Matrix::MakeTranslation(bounds.origin) * Matrix::MakeScale(scale), .sampler_descriptor = sampler_descriptor.value_or(sampler_descriptor_), - .opacity = opacity_}; + .opacity = opacity}; } return Contents::RenderToSnapshot( renderer, entity, sampler_descriptor.value_or(sampler_descriptor_)); @@ -136,7 +137,7 @@ frame_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); FS::FragInfo frag_info; - frag_info.alpha = opacity_; + frag_info.alpha = GetOpacity(); Command cmd; cmd.label = "Texture Fill";
diff --git a/impeller/entity/contents/texture_contents.h b/impeller/entity/contents/texture_contents.h index bea6254..2dd485f 100644 --- a/impeller/entity/contents/texture_contents.h +++ b/impeller/entity/contents/texture_contents.h
@@ -66,7 +66,7 @@ RenderPass& pass) const override; // |Contents| - bool CanAcceptOpacity(const Entity& entity) const override; + bool CanInheritOpacity(const Entity& entity) const override; // |Contents| void SetInheritedOpacity(Scalar opacity) override; @@ -83,6 +83,7 @@ SamplerDescriptor sampler_descriptor_ = {}; Rect source_rect_; Scalar opacity_ = 1.0f; + Scalar inherited_opacity_ = 1.0f; bool defer_applying_opacity_ = false; FML_DISALLOW_COPY_AND_ASSIGN(TextureContents);
diff --git a/impeller/entity/contents/tiled_texture_contents.cc b/impeller/entity/contents/tiled_texture_contents.cc index fa0f8f9..90b6b2b 100644 --- a/impeller/entity/contents/tiled_texture_contents.cc +++ b/impeller/entity/contents/tiled_texture_contents.cc
@@ -109,7 +109,7 @@ FS::FragInfo frag_info; frag_info.x_tile_mode = static_cast<Scalar>(x_tile_mode_); frag_info.y_tile_mode = static_cast<Scalar>(y_tile_mode_); - frag_info.alpha = GetAlpha(); + frag_info.alpha = GetOpacity(); Command cmd; cmd.label = "TiledTextureFill";
diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 0f8526b..dd5d3a9 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc
@@ -2387,10 +2387,12 @@ // Texture contents can always accept opacity. auto texture_contents = std::make_shared<TextureContents>(); texture_contents->SetOpacity(0.5); - ASSERT_TRUE(texture_contents->CanAcceptOpacity(entity)); + ASSERT_TRUE(texture_contents->CanInheritOpacity(entity)); texture_contents->SetInheritedOpacity(0.5); ASSERT_EQ(texture_contents->GetOpacity(), 0.25); + texture_contents->SetInheritedOpacity(0.5); + ASSERT_EQ(texture_contents->GetOpacity(), 0.25); // Solid color contents can accept opacity if their geometry // doesn't overlap. @@ -2399,22 +2401,26 @@ Geometry::MakeRect(Rect::MakeLTRB(100, 100, 200, 200))); solid_color->SetColor(Color::Blue().WithAlpha(0.5)); - ASSERT_TRUE(solid_color->CanAcceptOpacity(entity)); + ASSERT_TRUE(solid_color->CanInheritOpacity(entity)); solid_color->SetInheritedOpacity(0.5); ASSERT_EQ(solid_color->GetColor().alpha, 0.25); + solid_color->SetInheritedOpacity(0.5); + ASSERT_EQ(solid_color->GetColor().alpha, 0.25); // Color source contents can accept opacity if their geometry // doesn't overlap. auto tiled_texture = std::make_shared<TiledTextureContents>(); tiled_texture->SetGeometry( Geometry::MakeRect(Rect::MakeLTRB(100, 100, 200, 200))); - tiled_texture->SetAlpha(0.5); + tiled_texture->SetOpacity(0.5); - ASSERT_TRUE(tiled_texture->CanAcceptOpacity(entity)); + ASSERT_TRUE(tiled_texture->CanInheritOpacity(entity)); tiled_texture->SetInheritedOpacity(0.5); - ASSERT_EQ(tiled_texture->GetAlpha(), 0.25); + ASSERT_EQ(tiled_texture->GetOpacity(), 0.25); + tiled_texture->SetInheritedOpacity(0.5); + ASSERT_EQ(tiled_texture->GetOpacity(), 0.25); // Text contents can accept opacity if the text frames do not // overlap @@ -2429,18 +2435,20 @@ text_contents->SetTextFrame(frame); text_contents->SetColor(Color::Blue().WithAlpha(0.5)); - ASSERT_TRUE(text_contents->CanAcceptOpacity(entity)); + ASSERT_TRUE(text_contents->CanInheritOpacity(entity)); text_contents->SetInheritedOpacity(0.5); ASSERT_EQ(text_contents->GetColor().alpha, 0.25); + text_contents->SetInheritedOpacity(0.5); + ASSERT_EQ(text_contents->GetColor().alpha, 0.25); // Clips and restores trivially accept opacity. - ASSERT_TRUE(ClipContents().CanAcceptOpacity(entity)); - ASSERT_TRUE(ClipRestoreContents().CanAcceptOpacity(entity)); + ASSERT_TRUE(ClipContents().CanInheritOpacity(entity)); + ASSERT_TRUE(ClipRestoreContents().CanInheritOpacity(entity)); // Runtime effect contents can't accept opacity. auto runtime_effect = std::make_shared<RuntimeEffectContents>(); - ASSERT_FALSE(runtime_effect->CanAcceptOpacity(entity)); + ASSERT_FALSE(runtime_effect->CanInheritOpacity(entity)); } } // namespace testing