Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Impeller] ensure that srcOver to src conversion takes stroke coverage into account. #54817

Merged
merged 11 commits into from
Aug 28, 2024
2 changes: 1 addition & 1 deletion impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ TEST_P(AiksTest, OpaqueEntitiesGetCoercedToSource) {
});

ASSERT_TRUE(entity.size() >= 1);
ASSERT_TRUE(contents->IsOpaque());
ASSERT_TRUE(contents->IsOpaque({}));
ASSERT_EQ(entity[0].GetBlendMode(), BlendMode::kSource);
}

Expand Down
2 changes: 1 addition & 1 deletion impeller/aiks/experimental_canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity,
entity.GetTransform());
entity.SetInheritedOpacity(transform_stack_.back().distributed_opacity);
if (entity.GetBlendMode() == BlendMode::kSourceOver &&
entity.GetContents()->IsOpaque()) {
entity.GetContents()->IsOpaque(entity.GetTransform())) {
entity.SetBlendMode(BlendMode::kSource);
}

Expand Down
5 changes: 5 additions & 0 deletions impeller/entity/contents/color_source_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,9 @@ void ColorSourceContents::SetInheritedOpacity(Scalar opacity) {
inherited_opacity_ = opacity;
}

bool ColorSourceContents::AppliesAlphaForStrokeCoverage(
const Matrix& transform) const {
return GetGeometry() && GetGeometry()->ComputeAlphaCoverage(transform) < 1.0;
}

} // namespace impeller
4 changes: 4 additions & 0 deletions impeller/entity/contents/color_source_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ class ColorSourceContents : public Contents {
return geom.GetPositionBuffer(renderer, entity, pass);
}

/// @brief Whether the entity should be treated as non-opaque due to stroke
/// geometry requiring alpha for coverage.
bool AppliesAlphaForStrokeCoverage(const Matrix& transform) const;

template <typename VertexShaderT>
bool DrawGeometry(const ContentContext& renderer,
const Entity& entity,
Expand Down
6 changes: 4 additions & 2 deletions impeller/entity/contents/conical_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ bool ConicalGradientContents::RenderSSBO(const ContentContext& renderer,
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.decal_border_color = decal_border_color_;
frag_info.alpha =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
if (focus_) {
frag_info.focus = focus_.value();
frag_info.focus_radius = focus_radius_;
Expand Down Expand Up @@ -137,7 +138,8 @@ bool ConicalGradientContents::RenderTexture(const ContentContext& renderer,
frag_info.texture_sampler_y_coord_scale =
gradient_texture->GetYCoordScale();
frag_info.alpha =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
frag_info.half_texel =
Vector2(0.5 / gradient_texture->GetSize().width,
0.5 / gradient_texture->GetSize().height);
Expand Down
2 changes: 1 addition & 1 deletion impeller/entity/contents/contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Contents::Contents() = default;

Contents::~Contents() = default;

bool Contents::IsOpaque() const {
bool Contents::IsOpaque(const Matrix& transform) const {
return false;
}

Expand Down
4 changes: 3 additions & 1 deletion impeller/entity/contents/contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ class Contents {
/// properties (e.g. the blend mode), clips/visibility culling, or
/// inherited opacity.
///
virtual bool IsOpaque() const;
/// @param transform The current transform matrix of the entity that will
/// render this contents.
virtual bool IsOpaque(const Matrix& transform) const;

//----------------------------------------------------------------------------
/// @brief Given the current pass space bounding rectangle of the clip
Expand Down
13 changes: 8 additions & 5 deletions impeller/entity/contents/linear_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void LinearGradientContents::SetTileMode(Entity::TileMode tile_mode) {
tile_mode_ = tile_mode;
}

bool LinearGradientContents::IsOpaque() const {
bool LinearGradientContents::IsOpaque(const Matrix& transform) const {
if (GetOpacityFactor() < 1 || tile_mode_ == Entity::TileMode::kDecal) {
return false;
}
Expand All @@ -53,7 +53,7 @@ bool LinearGradientContents::IsOpaque() const {
return false;
}
}
return true;
return !AppliesAlphaForStrokeCoverage(transform);
}

bool LinearGradientContents::CanApplyFastGradient() const {
Expand Down Expand Up @@ -176,7 +176,8 @@ bool LinearGradientContents::FastLinearGradient(const ContentContext& renderer,

FS::FragInfo frag_info;
frag_info.alpha =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());

FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));

Expand Down Expand Up @@ -231,7 +232,8 @@ bool LinearGradientContents::RenderTexture(const ContentContext& renderer,
frag_info.texture_sampler_y_coord_scale =
gradient_texture->GetYCoordScale();
frag_info.alpha =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
;
frag_info.half_texel =
Vector2(0.5 / gradient_texture->GetSize().width,
Expand Down Expand Up @@ -284,7 +286,8 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer,
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.decal_border_color = decal_border_color_;
frag_info.alpha =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
frag_info.start_to_end = end_point_ - start_point_;
frag_info.inverse_dot_start_to_end =
CalculateInverseDotStartToEnd(start_point_, end_point_);
Expand Down
2 changes: 1 addition & 1 deletion impeller/entity/contents/linear_gradient_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class LinearGradientContents final : public ColorSourceContents {
~LinearGradientContents() override;

// |Contents|
bool IsOpaque() const override;
bool IsOpaque(const Matrix& transform) const override;

// |Contents|
bool Render(const ContentContext& renderer,
Expand Down
10 changes: 6 additions & 4 deletions impeller/entity/contents/radial_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const std::vector<Scalar>& RadialGradientContents::GetStops() const {
return stops_;
}

bool RadialGradientContents::IsOpaque() const {
bool RadialGradientContents::IsOpaque(const Matrix& transform) const {
if (GetOpacityFactor() < 1 || tile_mode_ == Entity::TileMode::kDecal) {
return false;
}
Expand All @@ -52,7 +52,7 @@ bool RadialGradientContents::IsOpaque() const {
return false;
}
}
return true;
return !AppliesAlphaForStrokeCoverage(transform);
}

bool RadialGradientContents::Render(const ContentContext& renderer,
Expand Down Expand Up @@ -86,7 +86,8 @@ bool RadialGradientContents::RenderSSBO(const ContentContext& renderer,
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.decal_border_color = decal_border_color_;
frag_info.alpha =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());

auto& host_buffer = renderer.GetTransientsBuffer();
auto colors = CreateGradientColors(colors_, stops_);
Expand Down Expand Up @@ -136,7 +137,8 @@ bool RadialGradientContents::RenderTexture(const ContentContext& renderer,
frag_info.texture_sampler_y_coord_scale =
gradient_texture->GetYCoordScale();
frag_info.alpha =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
frag_info.half_texel =
Vector2(0.5 / gradient_texture->GetSize().width,
0.5 / gradient_texture->GetSize().height);
Expand Down
2 changes: 1 addition & 1 deletion impeller/entity/contents/radial_gradient_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class RadialGradientContents final : public ColorSourceContents {
~RadialGradientContents() override;

// |Contents|
bool IsOpaque() const override;
bool IsOpaque(const Matrix& transform) const override;

// |Contents|
bool Render(const ContentContext& renderer,
Expand Down
8 changes: 4 additions & 4 deletions impeller/entity/contents/solid_color_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ bool SolidColorContents::IsSolidColor() const {
return true;
}

bool SolidColorContents::IsOpaque() const {
return GetColor().IsOpaque();
bool SolidColorContents::IsOpaque(const Matrix& transform) const {
return GetColor().IsOpaque() && !AppliesAlphaForStrokeCoverage(transform);
}

std::optional<Rect> SolidColorContents::GetCoverage(
Expand All @@ -54,8 +54,8 @@ bool SolidColorContents::Render(const ContentContext& renderer,

VS::FrameInfo frame_info;
FS::FragInfo frag_info;
frag_info.color =
GetColor().Premultiply() * GetGeometry()->ComputeAlphaCoverage(entity);
frag_info.color = GetColor().Premultiply() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());

PipelineBuilderCallback pipeline_callback =
[&renderer](ContentContextOptions options) {
Expand Down
2 changes: 1 addition & 1 deletion impeller/entity/contents/solid_color_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class SolidColorContents final : public ColorSourceContents {
bool IsSolidColor() const override;

// |Contents|
bool IsOpaque() const override;
bool IsOpaque(const Matrix& transform) const override;

// |Contents|
std::optional<Rect> GetCoverage(const Entity& entity) const override;
Expand Down
10 changes: 6 additions & 4 deletions impeller/entity/contents/sweep_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const std::vector<Scalar>& SweepGradientContents::GetStops() const {
return stops_;
}

bool SweepGradientContents::IsOpaque() const {
bool SweepGradientContents::IsOpaque(const Matrix& transform) const {
if (GetOpacityFactor() < 1 || tile_mode_ == Entity::TileMode::kDecal) {
return false;
}
Expand All @@ -58,7 +58,7 @@ bool SweepGradientContents::IsOpaque() const {
return false;
}
}
return true;
return !AppliesAlphaForStrokeCoverage(transform);
}

bool SweepGradientContents::Render(const ContentContext& renderer,
Expand Down Expand Up @@ -95,7 +95,8 @@ bool SweepGradientContents::RenderSSBO(const ContentContext& renderer,
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.decal_border_color = decal_border_color_;
frag_info.alpha =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());

auto& host_buffer = renderer.GetTransientsBuffer();
auto colors = CreateGradientColors(colors_, stops_);
Expand Down Expand Up @@ -147,7 +148,8 @@ bool SweepGradientContents::RenderTexture(const ContentContext& renderer,
frag_info.tile_mode = static_cast<Scalar>(tile_mode_);
frag_info.decal_border_color = decal_border_color_;
frag_info.alpha =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
frag_info.half_texel =
Vector2(0.5 / gradient_texture->GetSize().width,
0.5 / gradient_texture->GetSize().height);
Expand Down
2 changes: 1 addition & 1 deletion impeller/entity/contents/sweep_gradient_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class SweepGradientContents final : public ColorSourceContents {
~SweepGradientContents() override;

// |Contents|
bool IsOpaque() const override;
bool IsOpaque(const Matrix& transform) const override;

// |Contents|
bool Render(const ContentContext& renderer,
Expand Down
10 changes: 6 additions & 4 deletions impeller/entity/contents/tiled_texture_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,15 @@ bool TiledTextureContents::UsesEmulatedTileMode(
}

// |Contents|
bool TiledTextureContents::IsOpaque() const {
bool TiledTextureContents::IsOpaque(const Matrix& transform) const {
if (GetOpacityFactor() < 1 || x_tile_mode_ == Entity::TileMode::kDecal ||
y_tile_mode_ == Entity::TileMode::kDecal) {
return false;
}
if (color_filter_) {
return false;
}
return texture_->IsOpaque();
return texture_->IsOpaque() && !AppliesAlphaForStrokeCoverage(transform);
}

bool TiledTextureContents::Render(const ContentContext& renderer,
Expand Down Expand Up @@ -160,14 +160,16 @@ bool TiledTextureContents::Render(const ContentContext& renderer,
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 =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
FSExternal::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
} else {
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 =
GetOpacityFactor() * GetGeometry()->ComputeAlphaCoverage(entity);
GetOpacityFactor() *
GetGeometry()->ComputeAlphaCoverage(entity.GetTransform());
FS::BindFragInfo(pass, host_buffer.EmplaceUniform(frag_info));
}

Expand Down
2 changes: 1 addition & 1 deletion impeller/entity/contents/tiled_texture_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class TiledTextureContents final : public ColorSourceContents {
std::function<std::shared_ptr<ColorFilterContents>(FilterInput::Ref)>;

// |Contents|
bool IsOpaque() const override;
bool IsOpaque(const Matrix& transform) const override;

// |Contents|
bool Render(const ContentContext& renderer,
Expand Down
6 changes: 4 additions & 2 deletions impeller/entity/entity.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ bool Entity::CanInheritOpacity() const {
if (!contents_) {
return false;
}
if (!((blend_mode_ == BlendMode::kSource && contents_->IsOpaque()) ||
if (!((blend_mode_ == BlendMode::kSource &&
contents_->IsOpaque(GetTransform())) ||
blend_mode_ == BlendMode::kSourceOver)) {
return false;
}
Expand All @@ -137,7 +138,8 @@ bool Entity::SetInheritedOpacity(Scalar alpha) {
if (!CanInheritOpacity()) {
return false;
}
if (blend_mode_ == BlendMode::kSource && contents_->IsOpaque()) {
if (blend_mode_ == BlendMode::kSource &&
contents_->IsOpaque(GetTransform())) {
blend_mode_ = BlendMode::kSourceOver;
}
contents_->SetInheritedOpacity(alpha);
Expand Down
2 changes: 1 addition & 1 deletion impeller/entity/entity_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ bool EntityPass::GetBoundsLimitIsSnug() const {

void EntityPass::AddEntity(Entity entity) {
if (entity.GetBlendMode() == BlendMode::kSourceOver &&
entity.GetContents()->IsOpaque()) {
entity.GetContents()->IsOpaque(entity.GetTransform())) {
entity.SetBlendMode(BlendMode::kSource);
}

Expand Down
Loading