Skip to content

Commit 8075d38

Browse files
bderodnfield
authored andcommitted
Standardize around "coverage" terminology; make coverage optional everywhere (#118)
1 parent e09b0ed commit 8075d38

12 files changed

+115
-69
lines changed

impeller/entity/contents/contents.cc

+9-6
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,27 @@ Contents::Contents() = default;
2929

3030
Contents::~Contents() = default;
3131

32-
Rect Contents::GetBounds(const Entity& entity) const {
33-
return entity.GetTransformedPathBounds();
32+
std::optional<Rect> Contents::GetCoverage(const Entity& entity) const {
33+
return entity.GetPathCoverage();
3434
}
3535

3636
std::optional<Snapshot> Contents::RenderToTexture(
3737
const ContentContext& renderer,
3838
const Entity& entity) const {
39-
auto bounds = GetBounds(entity);
39+
auto bounds = GetCoverage(entity);
40+
if (!bounds.has_value()) {
41+
return std::nullopt;
42+
}
4043

4144
auto texture = renderer.MakeSubpass(
42-
ISize::Ceil(bounds.size),
45+
ISize::Ceil(bounds->size),
4346
[&contents = *this, &entity, &bounds](const ContentContext& renderer,
4447
RenderPass& pass) -> bool {
4548
Entity sub_entity;
4649
sub_entity.SetPath(entity.GetPath());
4750
sub_entity.SetBlendMode(Entity::BlendMode::kSource);
4851
sub_entity.SetTransformation(
49-
Matrix::MakeTranslation(Vector3(-bounds.origin)) *
52+
Matrix::MakeTranslation(Vector3(-bounds->origin)) *
5053
entity.GetTransformation());
5154
return contents.Render(renderer, sub_entity, pass);
5255
});
@@ -55,7 +58,7 @@ std::optional<Snapshot> Contents::RenderToTexture(
5558
return std::nullopt;
5659
}
5760

58-
return Snapshot{.texture = texture, .position = bounds.origin};
61+
return Snapshot{.texture = texture, .position = bounds->origin};
5962
}
6063

6164
} // namespace impeller

impeller/entity/contents/contents.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ class Contents {
3636
const Entity& entity,
3737
RenderPass& pass) const = 0;
3838

39-
/// @brief Get the bounding rectangle that this contents modifies in screen
40-
/// space.
41-
virtual Rect GetBounds(const Entity& entity) const;
39+
/// @brief Get the screen space bounding rectangle that this contents affects.
40+
virtual std::optional<Rect> GetCoverage(const Entity& entity) const;
4241

4342
/// @brief Render this contents to a texture, respecting the entity's
4443
/// transform, path, stencil depth, blend mode, etc.
45-
/// The result texture size is always the size of `GetBounds(entity)`.
44+
/// The result texture size is always the size of
45+
/// `GetCoverage(entity)`.
4646
virtual std::optional<Snapshot> RenderToTexture(
4747
const ContentContext& renderer,
4848
const Entity& entity) const;

impeller/entity/contents/filters/filter_contents.cc

+27-15
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ void FilterContents::SetInputs(FilterInput::Vector inputs) {
9595
bool FilterContents::Render(const ContentContext& renderer,
9696
const Entity& entity,
9797
RenderPass& pass) const {
98+
auto filter_coverage = GetCoverage(entity);
99+
if (!filter_coverage.has_value()) {
100+
return true;
101+
}
102+
98103
// Run the filter.
99104

100105
auto maybe_snapshot = RenderToTexture(renderer, entity);
@@ -110,49 +115,56 @@ bool FilterContents::Render(const ContentContext& renderer,
110115
contents->SetSourceRect(Rect::MakeSize(Size(snapshot.texture->GetSize())));
111116

112117
Entity e;
113-
e.SetPath(PathBuilder{}.AddRect(GetBounds(entity)).GetCurrentPath());
118+
e.SetPath(PathBuilder{}.AddRect(filter_coverage.value()).GetCurrentPath());
114119
e.SetBlendMode(entity.GetBlendMode());
115120
e.SetStencilDepth(entity.GetStencilDepth());
116121
return contents->Render(renderer, e, pass);
117122
}
118123

119-
Rect FilterContents::GetBounds(const Entity& entity) const {
120-
// The default bounds of FilterContents is just the union of its inputs.
121-
// FilterContents implementations may choose to increase the bounds in any
122-
// direction, but it should never
124+
std::optional<Rect> FilterContents::GetCoverage(const Entity& entity) const {
125+
// The default coverage of FilterContents is just the union of its inputs'
126+
// coverage. FilterContents implementations may choose to adjust this
127+
// coverage depending on the use case.
123128

124129
if (inputs_.empty()) {
125-
return Rect();
130+
return std::nullopt;
126131
}
127132

128-
Rect result = inputs_.front()->GetBounds(entity);
129-
for (auto input_i = inputs_.begin() + 1; input_i < inputs_.end(); input_i++) {
130-
result.Union(input_i->get()->GetBounds(entity));
133+
std::optional<Rect> result;
134+
for (const auto& input : inputs_) {
135+
auto coverage = input->GetCoverage(entity);
136+
if (!coverage.has_value()) {
137+
continue;
138+
}
139+
if (!result.has_value()) {
140+
result = coverage;
141+
continue;
142+
}
143+
result = result->Union(result.value());
131144
}
132-
133145
return result;
134146
}
135147

136148
std::optional<Snapshot> FilterContents::RenderToTexture(
137149
const ContentContext& renderer,
138150
const Entity& entity) const {
139-
auto bounds = GetBounds(entity);
140-
if (bounds.IsZero()) {
151+
auto bounds = GetCoverage(entity);
152+
if (!bounds.has_value() || bounds->IsEmpty()) {
141153
return std::nullopt;
142154
}
143155

144156
// Render the filter into a new texture.
145157
auto texture = renderer.MakeSubpass(
146-
ISize(GetBounds(entity).size),
158+
ISize(bounds->size),
147159
[=](const ContentContext& renderer, RenderPass& pass) -> bool {
148-
return RenderFilter(inputs_, renderer, entity, pass, bounds);
160+
return RenderFilter(inputs_, renderer, entity, pass, bounds.value());
149161
});
150162

151163
if (!texture) {
152164
return std::nullopt;
153165
}
154166

155-
return Snapshot{.texture = texture, .position = bounds.origin};
167+
return Snapshot{.texture = texture, .position = bounds->origin};
156168
}
157169

158170
} // namespace impeller

impeller/entity/contents/filters/filter_contents.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class FilterContents : public Contents {
6161
RenderPass& pass) const override;
6262

6363
// |Contents|
64-
Rect GetBounds(const Entity& entity) const override;
64+
std::optional<Rect> GetCoverage(const Entity& entity) const override;
6565

6666
// |Contents|
6767
virtual std::optional<Snapshot> RenderToTexture(

impeller/entity/contents/filters/filter_input.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ FilterInput::Variant FilterInput::GetInput() const {
3030
return input_;
3131
}
3232

33-
Rect FilterInput::GetBounds(const Entity& entity) const {
33+
std::optional<Rect> FilterInput::GetCoverage(const Entity& entity) const {
3434
if (snapshot_) {
3535
return Rect(snapshot_->position, Size(snapshot_->texture->GetSize()));
3636
}
3737

3838
if (auto contents = std::get_if<std::shared_ptr<Contents>>(&input_)) {
39-
return contents->get()->GetBounds(entity);
39+
return contents->get()->GetCoverage(entity);
4040
}
4141

4242
if (auto texture = std::get_if<std::shared_ptr<Texture>>(&input_)) {
43-
return entity.GetTransformedPathBounds();
43+
return entity.GetPathCoverage();
4444
}
4545

4646
FML_UNREACHABLE();

impeller/entity/contents/filters/filter_input.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class FilterInput final {
4242

4343
Variant GetInput() const;
4444

45-
Rect GetBounds(const Entity& entity) const;
45+
std::optional<Rect> GetCoverage(const Entity& entity) const;
4646

4747
std::optional<Snapshot> GetSnapshot(const ContentContext& renderer,
4848
const Entity& entity) const;

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

+45-24
Original file line numberDiff line numberDiff line change
@@ -78,38 +78,55 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter(
7878
auto& host_buffer = pass.GetTransientsBuffer();
7979

8080
auto input = inputs[0]->GetSnapshot(renderer, entity);
81-
auto input_bounds = inputs[0]->GetBounds(entity);
82-
auto filter_bounds = GetBounds(entity);
81+
if (!input.has_value()) {
82+
return true;
83+
}
84+
85+
auto input_bounds = inputs[0]->GetCoverage(entity);
86+
if (!input_bounds.has_value() || input_bounds->IsEmpty()) {
87+
return true;
88+
}
89+
auto filter_bounds = GetCoverage(entity);
90+
if (!filter_bounds.has_value() || filter_bounds->IsEmpty()) {
91+
FML_LOG(ERROR) << "The gaussian blur filter coverage is missing or empty "
92+
"even though the filter's input has coverage.";
93+
return false;
94+
}
8395

8496
auto transformed_blur =
8597
entity.GetTransformation().TransformDirection(blur_vector_);
8698

8799
// LTRB
88100
Scalar uv[4] = {
89-
(filter_bounds.GetLeft() - input_bounds.GetLeft()) /
90-
input_bounds.size.width,
91-
(filter_bounds.GetTop() - input_bounds.GetTop()) /
92-
input_bounds.size.height,
93-
1 + (filter_bounds.GetRight() - input_bounds.GetRight()) /
94-
input_bounds.size.width,
95-
1 + (filter_bounds.GetBottom() - input_bounds.GetBottom()) /
96-
input_bounds.size.height,
101+
(filter_bounds->GetLeft() - input_bounds->GetLeft()) /
102+
input_bounds->size.width,
103+
(filter_bounds->GetTop() - input_bounds->GetTop()) /
104+
input_bounds->size.height,
105+
1 + (filter_bounds->GetRight() - input_bounds->GetRight()) /
106+
input_bounds->size.width,
107+
1 + (filter_bounds->GetBottom() - input_bounds->GetBottom()) /
108+
input_bounds->size.height,
97109
};
98110

99111
auto source = source_override_ ? source_override_ : inputs[0];
100112
auto source_texture = source->GetSnapshot(renderer, entity);
101-
auto source_bounds = source->GetBounds(entity);
113+
auto source_bounds = source->GetCoverage(entity);
114+
if (!source_texture.has_value() || !source_bounds.has_value() ||
115+
source_bounds->IsEmpty()) {
116+
VALIDATION_LOG << "The gaussian blur source override has no coverage.";
117+
return false;
118+
}
102119

103120
// LTRB
104121
Scalar uv_src[4] = {
105-
(filter_bounds.GetLeft() - source_bounds.GetLeft()) /
106-
source_bounds.size.width,
107-
(filter_bounds.GetTop() - source_bounds.GetTop()) /
108-
source_bounds.size.height,
109-
1 + (filter_bounds.GetRight() - source_bounds.GetRight()) /
110-
source_bounds.size.width,
111-
1 + (filter_bounds.GetBottom() - source_bounds.GetBottom()) /
112-
source_bounds.size.height,
122+
(filter_bounds->GetLeft() - source_bounds->GetLeft()) /
123+
source_bounds->size.width,
124+
(filter_bounds->GetTop() - source_bounds->GetTop()) /
125+
source_bounds->size.height,
126+
1 + (filter_bounds->GetRight() - source_bounds->GetRight()) /
127+
source_bounds->size.width,
128+
1 + (filter_bounds->GetBottom() - source_bounds->GetBottom()) /
129+
source_bounds->size.height,
113130
};
114131

115132
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
@@ -124,7 +141,7 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter(
124141
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
125142

126143
VS::FrameInfo frame_info;
127-
frame_info.texture_size = Point(input_bounds.size);
144+
frame_info.texture_size = Point(input_bounds->size);
128145
frame_info.blur_radius = transformed_blur.GetLength();
129146
frame_info.blur_direction = transformed_blur.Normalize();
130147
frame_info.src_factor = src_color_factor_;
@@ -150,13 +167,17 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter(
150167
return pass.AddCommand(cmd);
151168
}
152169

153-
Rect DirectionalGaussianBlurFilterContents::GetBounds(
170+
std::optional<Rect> DirectionalGaussianBlurFilterContents::GetCoverage(
154171
const Entity& entity) const {
155-
auto bounds = FilterContents::GetBounds(entity);
172+
auto bounds = FilterContents::GetCoverage(entity);
173+
if (!bounds.has_value()) {
174+
return std::nullopt;
175+
}
176+
156177
auto transformed_blur =
157178
entity.GetTransformation().TransformDirection(blur_vector_).Abs();
158-
auto extent = bounds.size + transformed_blur * 2;
159-
return Rect(bounds.origin - transformed_blur, Size(extent.x, extent.y));
179+
auto extent = bounds->size + transformed_blur * 2;
180+
return Rect(bounds->origin - transformed_blur, Size(extent.x, extent.y));
160181
}
161182

162183
} // namespace impeller

impeller/entity/contents/filters/gaussian_blur_filter_contents.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents {
2525
void SetSourceOverride(FilterInput::Ref alpha_mask);
2626

2727
// |Contents|
28-
Rect GetBounds(const Entity& entity) const override;
28+
std::optional<Rect> GetCoverage(const Entity& entity) const override;
2929

3030
private:
3131
// |FilterContents|

impeller/entity/contents/snapshot.cc

+11-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "impeller/entity/contents/snapshot.h"
66

7+
#include <optional>
8+
79
#include "impeller/entity/contents/content_context.h"
810
#include "impeller/entity/contents/texture_contents.h"
911

@@ -13,28 +15,31 @@ std::optional<Snapshot> Snapshot::FromTransformedTexture(
1315
const ContentContext& renderer,
1416
const Entity& entity,
1517
std::shared_ptr<Texture> texture) {
16-
Rect bounds = entity.GetTransformedPathBounds();
18+
auto bounds = entity.GetPathCoverage();
19+
if (!bounds.has_value()) {
20+
return std::nullopt;
21+
}
1722

1823
auto result = renderer.MakeSubpass(
19-
ISize(bounds.size),
20-
[&texture, &entity, bounds](const ContentContext& renderer,
21-
RenderPass& pass) -> bool {
24+
ISize(bounds->size),
25+
[&texture, &entity, &bounds](const ContentContext& renderer,
26+
RenderPass& pass) -> bool {
2227
TextureContents contents;
2328
contents.SetTexture(texture);
2429
contents.SetSourceRect(Rect::MakeSize(Size(texture->GetSize())));
2530
Entity sub_entity;
2631
sub_entity.SetPath(entity.GetPath());
2732
sub_entity.SetBlendMode(Entity::BlendMode::kSource);
2833
sub_entity.SetTransformation(
29-
Matrix::MakeTranslation(Vector3(-bounds.origin)) *
34+
Matrix::MakeTranslation(Vector3(-bounds->origin)) *
3035
entity.GetTransformation());
3136
return contents.Render(renderer, sub_entity, pass);
3237
});
3338
if (!result) {
3439
return std::nullopt;
3540
}
3641

37-
return Snapshot{.texture = result, .position = bounds.origin};
42+
return Snapshot{.texture = result, .position = bounds->origin};
3843
}
3944

4045
} // namespace impeller

impeller/entity/entity.cc

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "impeller/entity/entity.h"
66

7+
#include <optional>
8+
79
#include "impeller/base/validation.h"
810
#include "impeller/entity/contents/content_context.h"
911
#include "impeller/renderer/render_pass.h"
@@ -30,10 +32,10 @@ void Entity::SetPath(Path path) {
3032
path_ = std::move(path);
3133
}
3234

33-
Rect Entity::GetTransformedPathBounds() const {
35+
std::optional<Rect> Entity::GetPathCoverage() const {
3436
auto bounds = GetPath().GetBoundingBox();
3537
if (!bounds.has_value()) {
36-
return Rect();
38+
return std::nullopt;
3739
}
3840
return bounds->TransformBounds(GetTransformation());
3941
}
@@ -51,7 +53,7 @@ std::optional<Rect> Entity::GetCoverage() const {
5153
return std::nullopt;
5254
}
5355

54-
return contents_->GetBounds(*this);
56+
return contents_->GetCoverage(*this);
5557
}
5658

5759
void Entity::SetContents(std::shared_ptr<Contents> contents) {

impeller/entity/entity.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class Entity {
6565

6666
void SetPath(Path path);
6767

68-
Rect GetTransformedPathBounds() const;
68+
std::optional<Rect> GetPathCoverage() const;
6969

7070
void SetAddsToCoverage(bool adds);
7171

0 commit comments

Comments
 (0)