Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit a9fe542

Browse files
authored
[Impeller] Coerce opaque ColorSourceContents to Source (#41525)
This coercion happens when Entities are appended to a pass, which is the moment where we will need to perform depth sorting.
1 parent 526fd0d commit a9fe542

23 files changed

+226
-6
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,5 +2136,32 @@ TEST_P(AiksTest, CanRenderOffscreenCheckerboard) {
21362136
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
21372137
}
21382138

2139+
TEST_P(AiksTest, OpaqueEntitiesGetCoercedToSource) {
2140+
Canvas canvas;
2141+
canvas.Scale(Vector2(1.618, 1.618));
2142+
canvas.DrawCircle(Point(), 10,
2143+
{
2144+
.color = Color::CornflowerBlue(),
2145+
.blend_mode = BlendMode::kSourceOver,
2146+
});
2147+
Picture picture = canvas.EndRecordingAsPicture();
2148+
2149+
// Extract the SolidColorSource.
2150+
Entity entity;
2151+
std::shared_ptr<SolidColorContents> contents;
2152+
picture.pass->IterateAllEntities([&e = entity, &contents](Entity& entity) {
2153+
if (ScalarNearlyEqual(entity.GetTransformation().GetScale().x, 1.618f)) {
2154+
e = entity;
2155+
contents =
2156+
std::static_pointer_cast<SolidColorContents>(entity.GetContents());
2157+
return false;
2158+
}
2159+
return true;
2160+
});
2161+
2162+
ASSERT_TRUE(contents->IsOpaque());
2163+
ASSERT_EQ(entity.GetBlendMode(), BlendMode::kSource);
2164+
}
2165+
21392166
} // namespace testing
21402167
} // namespace impeller

impeller/aiks/color_source.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "impeller/entity/contents/solid_color_contents.h"
1818
#include "impeller/entity/contents/sweep_gradient_contents.h"
1919
#include "impeller/entity/contents/tiled_texture_contents.h"
20+
#include "impeller/geometry/color.h"
2021
#include "impeller/geometry/matrix.h"
2122
#include "impeller/geometry/scalar.h"
2223
#include "impeller/runtime_stage/runtime_stage.h"

impeller/aiks/paint_pass_delegate.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "impeller/entity/contents/contents.h"
88
#include "impeller/entity/contents/texture_contents.h"
99
#include "impeller/entity/entity_pass.h"
10+
#include "impeller/geometry/color.h"
1011
#include "impeller/geometry/path_builder.h"
1112

1213
namespace impeller {
@@ -72,6 +73,8 @@ bool OpacityPeepholePassDelegate::CanElide() {
7273
// |EntityPassDelgate|
7374
bool OpacityPeepholePassDelegate::CanCollapseIntoParentPass(
7475
EntityPass* entity_pass) {
76+
// OpacityPeepholePassDelegate will only get used if the pass's blend mode is
77+
// SourceOver, so no need to check here.
7578
if (paint_.color.alpha <= 0.0 || paint_.color.alpha >= 1.0 ||
7679
paint_.image_filter.has_value() || paint_.color_filter.has_value()) {
7780
return false;
@@ -97,7 +100,7 @@ bool OpacityPeepholePassDelegate::CanCollapseIntoParentPass(
97100
auto had_subpass = entity_pass->IterateUntilSubpass(
98101
[&all_coverages, &all_can_accept](Entity& entity) {
99102
auto contents = entity.GetContents();
100-
if (!contents->CanInheritOpacity(entity)) {
103+
if (!entity.CanInheritOpacity()) {
101104
all_can_accept = false;
102105
return false;
103106
}
@@ -119,7 +122,7 @@ bool OpacityPeepholePassDelegate::CanCollapseIntoParentPass(
119122
}
120123
auto alpha = paint_.color.alpha;
121124
entity_pass->IterateUntilSubpass([&alpha](Entity& entity) {
122-
entity.GetContents()->SetInheritedOpacity(alpha);
125+
entity.SetInheritedOpacity(alpha);
123126
return true;
124127
});
125128
return true;

impeller/core/texture.cc

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ Texture::~Texture() = default;
1414

1515
bool Texture::SetContents(const uint8_t* contents,
1616
size_t length,
17-
size_t slice) {
17+
size_t slice,
18+
bool is_opaque) {
1819
if (!IsSliceValid(slice)) {
1920
VALIDATION_LOG << "Invalid slice for texture.";
2021
return false;
@@ -23,11 +24,13 @@ bool Texture::SetContents(const uint8_t* contents,
2324
return false;
2425
}
2526
intent_ = TextureIntent::kUploadFromHost;
27+
is_opaque_ = is_opaque;
2628
return true;
2729
}
2830

2931
bool Texture::SetContents(std::shared_ptr<const fml::Mapping> mapping,
30-
size_t slice) {
32+
size_t slice,
33+
bool is_opaque) {
3134
if (!IsSliceValid(slice)) {
3235
VALIDATION_LOG << "Invalid slice for texture.";
3336
return false;
@@ -39,9 +42,14 @@ bool Texture::SetContents(std::shared_ptr<const fml::Mapping> mapping,
3942
return false;
4043
}
4144
intent_ = TextureIntent::kUploadFromHost;
45+
is_opaque_ = is_opaque;
4246
return true;
4347
}
4448

49+
bool Texture::IsOpaque() const {
50+
return is_opaque_;
51+
}
52+
4553
size_t Texture::GetMipCount() const {
4654
return GetTextureDescriptor().mip_count;
4755
}

impeller/core/texture.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,19 @@ class Texture {
2222

2323
[[nodiscard]] bool SetContents(const uint8_t* contents,
2424
size_t length,
25-
size_t slice = 0);
25+
size_t slice = 0,
26+
bool is_opaque = false);
2627

2728
[[nodiscard]] bool SetContents(std::shared_ptr<const fml::Mapping> mapping,
28-
size_t slice = 0);
29+
size_t slice = 0,
30+
bool is_opaque = false);
2931

3032
virtual bool IsValid() const = 0;
3133

3234
virtual ISize GetSize() const = 0;
3335

36+
bool IsOpaque() const;
37+
3438
size_t GetMipCount() const;
3539

3640
const TextureDescriptor& GetTextureDescriptor() const;
@@ -59,6 +63,7 @@ class Texture {
5963
private:
6064
TextureIntent intent_ = TextureIntent::kRenderToTexture;
6165
const TextureDescriptor desc_;
66+
bool is_opaque_ = false;
6267

6368
bool IsSliceValid(size_t slice) const;
6469

impeller/entity/contents/conical_gradient_contents.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ void ConicalGradientContents::SetFocus(std::optional<Point> focus,
5151
focus_radius_ = radius;
5252
}
5353

54+
bool ConicalGradientContents::IsOpaque() const {
55+
if (GetOpacity() < 1) {
56+
return false;
57+
}
58+
for (auto color : colors_) {
59+
if (!color.IsOpaque()) {
60+
return false;
61+
}
62+
}
63+
return true;
64+
}
65+
5466
bool ConicalGradientContents::Render(const ContentContext& renderer,
5567
const Entity& entity,
5668
RenderPass& pass) const {

impeller/entity/contents/conical_gradient_contents.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class ConicalGradientContents final : public ColorSourceContents {
2424

2525
~ConicalGradientContents() override;
2626

27+
// |Contents|
28+
bool IsOpaque() const override;
29+
2730
// |Contents|
2831
bool Render(const ContentContext& renderer,
2932
const Entity& entity,

impeller/entity/contents/contents.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ Contents::Contents() = default;
4545

4646
Contents::~Contents() = default;
4747

48+
bool Contents::IsOpaque() const {
49+
return false;
50+
}
51+
4852
Contents::StencilCoverage Contents::GetStencilCoverage(
4953
const Entity& entity,
5054
const std::optional<Rect>& current_stencil_coverage) const {

impeller/entity/contents/contents.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ class Contents {
5656
/// @brief Get the screen space bounding rectangle that this contents affects.
5757
virtual std::optional<Rect> GetCoverage(const Entity& entity) const = 0;
5858

59+
/// @brief Whether this Contents only emits opaque source colors from the
60+
/// fragment stage. This value does not account for any entity
61+
/// properties (e.g. the blend mode), clips/visibility culling, or
62+
/// inherited opacity.
63+
virtual bool IsOpaque() const;
64+
5965
/// @brief Given the current screen space bounding rectangle of the stencil,
6066
/// return the expected stencil coverage after this draw call. This
6167
/// should only be implemented for contents that may write to the

impeller/entity/contents/linear_gradient_contents.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ void LinearGradientContents::SetTileMode(Entity::TileMode tile_mode) {
4444
tile_mode_ = tile_mode;
4545
}
4646

47+
bool LinearGradientContents::IsOpaque() const {
48+
if (GetOpacity() < 1) {
49+
return false;
50+
}
51+
for (auto color : colors_) {
52+
if (!color.IsOpaque()) {
53+
return false;
54+
}
55+
}
56+
return true;
57+
}
58+
4759
bool LinearGradientContents::Render(const ContentContext& renderer,
4860
const Entity& entity,
4961
RenderPass& pass) const {

0 commit comments

Comments
 (0)