Skip to content

Commit 4417fa6

Browse files
chinmaygardednfield
authored andcommitted
Don't let subpass coverage exceed entity coverage.
1 parent 8e90d38 commit 4417fa6

File tree

11 files changed

+82
-47
lines changed

11 files changed

+82
-47
lines changed

impeller/aiks/aiks_unittests.cc

+2-3
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,8 @@ TEST_F(AiksTest, CanPerformSaveLayerWithBounds) {
197197
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
198198
}
199199

200-
TEST_F(
201-
AiksTest,
202-
DISABLED_CanPerformSaveLayerWithBoundsAndLargerIntermediateIsNotAllocated) {
200+
TEST_F(AiksTest,
201+
CanPerformSaveLayerWithBoundsAndLargerIntermediateIsNotAllocated) {
203202
Canvas canvas;
204203

205204
Paint red;

impeller/aiks/canvas.cc

+1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ void Canvas::ClipPath(Path path) {
132132
entity.SetPath(std::move(path));
133133
entity.SetContents(std::make_shared<ClipContents>());
134134
entity.SetStencilDepth(GetStencilDepth());
135+
entity.SetAddsToCoverage(false);
135136

136137
GetCurrentPass().AddEntity(std::move(entity));
137138
}

impeller/entity/contents.cc

+7-2
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,12 @@ bool TextureContents::Render(const ContentRenderer& renderer,
205205
using FS = TextureFillFragmentShader;
206206

207207
const auto coverage_rect = entity.GetPath().GetBoundingBox();
208-
if (coverage_rect.size.IsEmpty()) {
208+
209+
if (!coverage_rect.has_value()) {
210+
return true;
211+
}
212+
213+
if (coverage_rect->size.IsEmpty()) {
209214
return true;
210215
}
211216

@@ -226,7 +231,7 @@ bool TextureContents::Render(const ContentRenderer& renderer,
226231
VS::PerVertexData data;
227232
data.vertices = vtx;
228233
data.texture_coords =
229-
((vtx - coverage_rect.origin) / coverage_rect.size);
234+
((vtx - coverage_rect->origin) / coverage_rect->size);
230235
vertex_builder.AppendVertex(data);
231236
});
232237
if (!tess_result) {

impeller/entity/entity.cc

+16
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ void Entity::SetPath(Path path) {
2929
path_ = std::move(path);
3030
}
3131

32+
void Entity::SetAddsToCoverage(bool adds) {
33+
adds_to_coverage_ = adds;
34+
}
35+
36+
bool Entity::AddsToCoverage() const {
37+
return adds_to_coverage_;
38+
}
39+
40+
std::optional<Rect> Entity::GetCoverage() const {
41+
if (!adds_to_coverage_) {
42+
return std::nullopt;
43+
}
44+
45+
return path_.GetBoundingBox();
46+
}
47+
3248
void Entity::SetContents(std::shared_ptr<Contents> contents) {
3349
contents_ = std::move(contents);
3450
}

impeller/entity/entity.h

+7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ class Entity {
3030

3131
void SetPath(Path path);
3232

33+
void SetAddsToCoverage(bool adds);
34+
35+
bool AddsToCoverage() const;
36+
37+
std::optional<Rect> GetCoverage() const;
38+
3339
void SetContents(std::shared_ptr<Contents> contents);
3440

3541
const std::shared_ptr<Contents>& GetContents() const;
@@ -47,6 +53,7 @@ class Entity {
4753
std::shared_ptr<Contents> contents_;
4854
Path path_;
4955
uint32_t stencil_depth_ = 0u;
56+
bool adds_to_coverage_ = true;
5057
};
5158

5259
} // namespace impeller

impeller/entity/entity_pass.cc

+37-30
Original file line numberDiff line numberDiff line change
@@ -43,27 +43,41 @@ size_t EntityPass::GetSubpassesDepth() const {
4343
return max_subpass_depth + 1u;
4444
}
4545

46-
Rect EntityPass::GetCoverageRect() const {
47-
std::optional<Point> min, max;
46+
std::optional<Rect> EntityPass::GetEntitiesCoverage() const {
47+
std::optional<Rect> result;
4848
for (const auto& entity : entities_) {
49-
auto coverage = entity.GetPath().GetMinMaxCoveragePoints();
50-
if (!coverage.has_value()) {
49+
auto coverage = entity.GetCoverage();
50+
if (!result.has_value() && coverage.has_value()) {
51+
result = coverage;
5152
continue;
5253
}
53-
if (!min.has_value()) {
54-
min = coverage->first;
55-
}
56-
if (!max.has_value()) {
57-
max = coverage->second;
54+
if (!coverage.has_value()) {
55+
continue;
5856
}
59-
min = min->Min(coverage->first);
60-
max = max->Max(coverage->second);
57+
result = result->Union(coverage.value());
58+
}
59+
return result;
60+
}
61+
62+
std::optional<Rect> EntityPass::GetSubpassCoverage(
63+
const EntityPass& subpass) const {
64+
auto entities_coverage = subpass.GetEntitiesCoverage();
65+
// The entities don't cover anything. There is nothing to do.
66+
if (!entities_coverage.has_value()) {
67+
return std::nullopt;
6168
}
62-
if (!min.has_value() || !max.has_value()) {
63-
return {};
69+
70+
// The delegates don't have an opinion on what the entity coverage has to be.
71+
// Just use that as-is.
72+
auto delegate_coverage = delegate_->GetCoverageRect();
73+
if (!delegate_coverage.has_value()) {
74+
return entities_coverage;
6475
}
65-
const auto diff = *max - *min;
66-
return {min->x, min->y, diff.x, diff.y};
76+
77+
// If the delete tells us the coverage is smaller than it needs to be, then
78+
// great. OTOH, if the delegate is being wasteful, limit coverage to what is
79+
// actually needed.
80+
return entities_coverage->Intersection(delegate_coverage.value());
6781
}
6882

6983
EntityPass* EntityPass::GetSuperpass() const {
@@ -74,18 +88,6 @@ const EntityPass::Subpasses& EntityPass::GetSubpasses() const {
7488
return subpasses_;
7589
}
7690

77-
Rect EntityPass::GetSubpassCoverage(const EntityPass& subpass) const {
78-
auto subpass_coverage = subpass.GetCoverageRect();
79-
auto delegate_coverage =
80-
delegate_->GetCoverageRect().value_or(subpass_coverage);
81-
Rect coverage;
82-
coverage.origin = subpass_coverage.origin;
83-
// TODO(csg): This must still be restricted to the max texture size. Or,
84-
// decide if this must be done by the allocator.
85-
coverage.size = subpass_coverage.size.Min(delegate_coverage.size);
86-
return coverage;
87-
}
88-
8991
EntityPass* EntityPass::AddSubpass(std::unique_ptr<EntityPass> pass) {
9092
if (!pass) {
9193
return nullptr;
@@ -117,7 +119,11 @@ bool EntityPass::Render(ContentRenderer& renderer,
117119

118120
const auto subpass_coverage = GetSubpassCoverage(*subpass);
119121

120-
if (subpass_coverage.IsEmpty()) {
122+
if (!subpass_coverage.has_value()) {
123+
continue;
124+
}
125+
126+
if (subpass_coverage->size.IsEmpty()) {
121127
// It is not an error to have an empty subpass. But subpasses that can't
122128
// create their intermediates must trip errors.
123129
continue;
@@ -126,7 +132,7 @@ bool EntityPass::Render(ContentRenderer& renderer,
126132
auto context = renderer.GetContext();
127133

128134
auto subpass_target = RenderTarget::CreateOffscreen(
129-
*context, ISize::Ceil(subpass_coverage.size));
135+
*context, ISize::Ceil(subpass_coverage->size));
130136

131137
auto subpass_texture = subpass_target.GetRenderTargetTexture();
132138

@@ -178,7 +184,8 @@ bool EntityPass::Render(ContentRenderer& renderer,
178184
}
179185

180186
Entity entity;
181-
entity.SetPath(PathBuilder{}.AddRect(subpass_coverage).CreatePath());
187+
entity.SetPath(
188+
PathBuilder{}.AddRect(subpass_coverage.value()).CreatePath());
182189
entity.SetContents(std::move(offscreen_texture_contents));
183190
entity.SetStencilDepth(stencil_depth_);
184191
entity.SetTransformation(xformation_);

impeller/entity/entity_pass.h

+3-5
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ class EntityPass {
3333

3434
std::unique_ptr<EntityPass> Clone() const;
3535

36-
Rect GetCoverageRect() const;
37-
38-
// TODO(csg): This prevents an optimization where the coverage can be
39-
// calculated once in SetEntities an memoized.
4036
void AddEntity(Entity entity);
4137

4238
void SetEntities(Entities entities);
@@ -66,7 +62,9 @@ class EntityPass {
6662
std::unique_ptr<EntityPassDelegate> delegate_ =
6763
EntityPassDelegate::MakeDefault();
6864

69-
Rect GetSubpassCoverage(const EntityPass& subpass) const;
65+
std::optional<Rect> GetSubpassCoverage(const EntityPass& subpass) const;
66+
67+
std::optional<Rect> GetEntitiesCoverage() const;
7068

7169
FML_DISALLOW_COPY_AND_ASSIGN(EntityPass);
7270
};

impeller/geometry/geometry_unittests.cc

+4-2
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ TEST(GeometryTest, BoundingBoxCubic) {
185185
path.AddCubicComponent({120, 160}, {25, 200}, {220, 260}, {220, 40});
186186
auto box = path.GetBoundingBox();
187187
Rect expected(93.9101, 40, 126.09, 158.862);
188-
ASSERT_RECT_NEAR(box, expected);
188+
ASSERT_TRUE(box.has_value());
189+
ASSERT_RECT_NEAR(box.value(), expected);
189190
}
190191

191192
TEST(GeometryTest, BoundingBoxOfCompositePathIsCorrect) {
@@ -194,7 +195,8 @@ TEST(GeometryTest, BoundingBoxOfCompositePathIsCorrect) {
194195
auto path = builder.CreatePath();
195196
auto actual = path.GetBoundingBox();
196197
Rect expected(10, 10, 300, 300);
197-
ASSERT_RECT_NEAR(actual, expected);
198+
ASSERT_TRUE(actual.has_value());
199+
ASSERT_RECT_NEAR(actual.value(), expected);
198200
}
199201

200202
TEST(GeometryTest, CanGenerateMipCounts) {

impeller/geometry/path.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -173,15 +173,15 @@ std::vector<Point> Path::CreatePolyline(
173173
return points;
174174
}
175175

176-
Rect Path::GetBoundingBox() const {
176+
std::optional<Rect> Path::GetBoundingBox() const {
177177
auto min_max = GetMinMaxCoveragePoints();
178178
if (!min_max.has_value()) {
179-
return {};
179+
return std::nullopt;
180180
}
181181
auto min = min_max->first;
182182
auto max = min_max->second;
183183
const auto difference = max - min;
184-
return {min.x, min.y, difference.x, difference.y};
184+
return Rect{min.x, min.y, difference.x, difference.y};
185185
}
186186

187187
std::optional<std::pair<Point, Point>> Path::GetMinMaxCoveragePoints() const {

impeller/geometry/path.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class Path {
6767
std::vector<Point> CreatePolyline(
6868
const SmoothingApproximation& approximation = {}) const;
6969

70-
Rect GetBoundingBox() const;
70+
std::optional<Rect> GetBoundingBox() const;
7171

7272
std::optional<std::pair<Point, Point>> GetMinMaxCoveragePoints() const;
7373

impeller/renderer/renderer_unittests.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ TEST_F(RendererTest, CanRenderToTexture) {
266266

267267
TEST_F(RendererTest, CanRenderPath) {
268268
auto path = PathBuilder{}.AddCircle({550, 550}, 500).CreatePath();
269-
ASSERT_FALSE(path.GetBoundingBox().IsZero());
269+
ASSERT_FALSE(path.GetBoundingBox().has_value());
270270

271271
using BoxPipeline = PipelineT<BoxFadeVertexShader, BoxFadeFragmentShader>;
272272
using VS = BoxFadeVertexShader;

0 commit comments

Comments
 (0)