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

Commit d7f2f9e

Browse files
committed
[Impeller] Limit backdrop blur rendering to the current clip
1 parent c891f03 commit d7f2f9e

35 files changed

+248
-159
lines changed

impeller/entity/contents/contents.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ bool Contents::ShouldRender(const Entity& entity,
124124
return stencil_coverage->IntersectsWithRect(coverage.value());
125125
}
126126

127+
void Contents::SetCoverageHint(std::optional<Rect> coverage_hint) {
128+
coverage_hint_ = coverage_hint;
129+
}
130+
131+
const std::optional<Rect>& Contents::GetCoverageHint() const {
132+
return coverage_hint_;
133+
}
134+
127135
std::optional<Size> Contents::GetColorSourceSize() const {
128136
return color_source_size_;
129137
};

impeller/entity/contents/contents.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ 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 Hint that specifies the coverage area of this Contents that will
60+
/// actually be used during rendering. This is for optimization
61+
/// purposes only and can not be relied on as a clip. May optionally
62+
/// affect the result of `GetCoverage()`.
63+
void SetCoverageHint(std::optional<Rect> coverage_hint);
64+
65+
const std::optional<Rect>& GetCoverageHint() const;
66+
5967
/// @brief Whether this Contents only emits opaque source colors from the
6068
/// fragment stage. This value does not account for any entity
6169
/// properties (e.g. the blend mode), clips/visibility culling, or
@@ -110,6 +118,7 @@ class Contents {
110118
virtual void SetInheritedOpacity(Scalar opacity);
111119

112120
private:
121+
std::optional<Rect> coverage_hint_;
113122
std::optional<Size> color_source_size_;
114123

115124
FML_DISALLOW_COPY_AND_ASSIGN(Contents);

impeller/entity/contents/filters/blend_filter_contents.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,8 @@ std::optional<Entity> BlendFilterContents::RenderFilter(
649649
const ContentContext& renderer,
650650
const Entity& entity,
651651
const Matrix& effect_transform,
652-
const Rect& coverage) const {
652+
const Rect& coverage,
653+
const std::optional<Rect>& coverage_hint) const {
653654
if (inputs.empty()) {
654655
return std::nullopt;
655656
}

impeller/entity/contents/filters/blend_filter_contents.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ class BlendFilterContents : public ColorFilterContents {
3232

3333
private:
3434
// |FilterContents|
35-
std::optional<Entity> RenderFilter(const FilterInput::Vector& inputs,
36-
const ContentContext& renderer,
37-
const Entity& entity,
38-
const Matrix& effect_transform,
39-
const Rect& coverage) const override;
35+
std::optional<Entity> RenderFilter(
36+
const FilterInput::Vector& inputs,
37+
const ContentContext& renderer,
38+
const Entity& entity,
39+
const Matrix& effect_transform,
40+
const Rect& coverage,
41+
const std::optional<Rect>& coverage_hint) const override;
4042

4143
/// @brief Optimized advanced blend that avoids a second subpass when there is
4244
/// only a single input and a foreground color.

impeller/entity/contents/filters/border_mask_blur_filter_contents.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ std::optional<Entity> BorderMaskBlurFilterContents::RenderFilter(
5353
const ContentContext& renderer,
5454
const Entity& entity,
5555
const Matrix& effect_transform,
56-
const Rect& coverage) const {
56+
const Rect& coverage,
57+
const std::optional<Rect>& coverage_hint) const {
5758
using VS = BorderMaskBlurPipeline::VertexShader;
5859
using FS = BorderMaskBlurPipeline::FragmentShader;
5960

impeller/entity/contents/filters/border_mask_blur_filter_contents.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@ class BorderMaskBlurFilterContents final : public FilterContents {
2929

3030
private:
3131
// |FilterContents|
32-
std::optional<Entity> RenderFilter(const FilterInput::Vector& input_textures,
33-
const ContentContext& renderer,
34-
const Entity& entity,
35-
const Matrix& effect_transform,
36-
const Rect& coverage) const override;
32+
std::optional<Entity> RenderFilter(
33+
const FilterInput::Vector& input_textures,
34+
const ContentContext& renderer,
35+
const Entity& entity,
36+
const Matrix& effect_transform,
37+
const Rect& coverage,
38+
const std::optional<Rect>& coverage_hint) const override;
3739

3840
Sigma sigma_x_;
3941
Sigma sigma_y_;

impeller/entity/contents/filters/color_matrix_filter_contents.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ std::optional<Entity> ColorMatrixFilterContents::RenderFilter(
2929
const ContentContext& renderer,
3030
const Entity& entity,
3131
const Matrix& effect_transform,
32-
const Rect& coverage) const {
32+
const Rect& coverage,
33+
const std::optional<Rect>& coverage_hint) const {
3334
using VS = ColorMatrixColorFilterPipeline::VertexShader;
3435
using FS = ColorMatrixColorFilterPipeline::FragmentShader;
3536

impeller/entity/contents/filters/color_matrix_filter_contents.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ class ColorMatrixFilterContents final : public ColorFilterContents {
2424

2525
private:
2626
// |FilterContents|
27-
std::optional<Entity> RenderFilter(const FilterInput::Vector& input_textures,
28-
const ContentContext& renderer,
29-
const Entity& entity,
30-
const Matrix& effect_transform,
31-
const Rect& coverage) const override;
27+
std::optional<Entity> RenderFilter(
28+
const FilterInput::Vector& input_textures,
29+
const ContentContext& renderer,
30+
const Entity& entity,
31+
const Matrix& effect_transform,
32+
const Rect& coverage,
33+
const std::optional<Rect>& coverage_hint) const override;
3234

3335
ColorMatrix matrix_;
3436

impeller/entity/contents/filters/filter_contents.cc

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,6 @@ void FilterContents::SetInputs(FilterInput::Vector inputs) {
153153
inputs_ = std::move(inputs);
154154
}
155155

156-
void FilterContents::SetCoverageCrop(std::optional<Rect> coverage_crop) {
157-
coverage_crop_ = coverage_crop;
158-
}
159-
160156
void FilterContents::SetEffectTransform(Matrix effect_transform) {
161157
effect_transform_ = effect_transform;
162158
}
@@ -171,7 +167,7 @@ bool FilterContents::Render(const ContentContext& renderer,
171167

172168
// Run the filter.
173169

174-
auto maybe_entity = GetEntity(renderer, entity);
170+
auto maybe_entity = GetEntity(renderer, entity, GetCoverageHint());
175171
if (!maybe_entity.has_value()) {
176172
return true;
177173
}
@@ -181,8 +177,8 @@ bool FilterContents::Render(const ContentContext& renderer,
181177
std::optional<Rect> FilterContents::GetLocalCoverage(
182178
const Entity& local_entity) const {
183179
auto coverage = GetFilterCoverage(inputs_, local_entity, effect_transform_);
184-
if (coverage_crop_.has_value() && coverage.has_value()) {
185-
coverage = coverage->Intersection(coverage_crop_.value());
180+
if (GetCoverageHint().has_value() && coverage.has_value()) {
181+
coverage = coverage->Intersection(*GetCoverageHint());
186182
}
187183

188184
return coverage;
@@ -223,8 +219,10 @@ std::optional<Rect> FilterContents::GetFilterCoverage(
223219
return result;
224220
}
225221

226-
std::optional<Entity> FilterContents::GetEntity(const ContentContext& renderer,
227-
const Entity& entity) const {
222+
std::optional<Entity> FilterContents::GetEntity(
223+
const ContentContext& renderer,
224+
const Entity& entity,
225+
const std::optional<Rect>& coverage_hint) const {
228226
Entity entity_with_local_transform = entity;
229227
entity_with_local_transform.SetTransformation(
230228
GetTransform(entity.GetTransformation()));
@@ -235,7 +233,7 @@ std::optional<Entity> FilterContents::GetEntity(const ContentContext& renderer,
235233
}
236234

237235
return RenderFilter(inputs_, renderer, entity_with_local_transform,
238-
effect_transform_, coverage.value());
236+
effect_transform_, coverage.value(), coverage_hint);
239237
}
240238

241239
std::optional<Snapshot> FilterContents::RenderToSnapshot(
@@ -247,12 +245,13 @@ std::optional<Snapshot> FilterContents::RenderToSnapshot(
247245
const std::string& label) const {
248246
// Resolve the render instruction (entity) from the filter and render it to a
249247
// snapshot.
250-
if (std::optional<Entity> result = GetEntity(renderer, entity);
248+
if (std::optional<Entity> result =
249+
GetEntity(renderer, entity, coverage_limit);
251250
result.has_value()) {
252251
return result->GetContents()->RenderToSnapshot(
253252
renderer, // renderer
254253
result.value(), // entity
255-
std::nullopt, // coverage_limit
254+
coverage_limit, // coverage_limit
256255
std::nullopt, // sampler_descriptor
257256
true, // msaa_enabled
258257
label); // label

impeller/entity/contents/filters/filter_contents.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,15 @@ class FilterContents : public Contents {
102102
/// particular filter's implementation.
103103
void SetInputs(FilterInput::Vector inputs);
104104

105-
/// @brief Screen space bounds to use for cropping the filter output.
106-
void SetCoverageCrop(std::optional<Rect> coverage_crop);
107-
108105
/// @brief Sets the transform which gets appended to the effect of this
109106
/// filter. Note that this is in addition to the entity's transform.
110107
void SetEffectTransform(Matrix effect_transform);
111108

112109
/// @brief Create an Entity that renders this filter's output.
113-
std::optional<Entity> GetEntity(const ContentContext& renderer,
114-
const Entity& entity) const;
110+
std::optional<Entity> GetEntity(
111+
const ContentContext& renderer,
112+
const Entity& entity,
113+
const std::optional<Rect>& coverage_hint) const;
115114

116115
// |Contents|
117116
bool Render(const ContentContext& renderer,
@@ -141,16 +140,17 @@ class FilterContents : public Contents {
141140
const Matrix& effect_transform) const;
142141

143142
/// @brief Converts zero or more filter inputs into a render instruction.
144-
virtual std::optional<Entity> RenderFilter(const FilterInput::Vector& inputs,
145-
const ContentContext& renderer,
146-
const Entity& entity,
147-
const Matrix& effect_transform,
148-
const Rect& coverage) const = 0;
143+
virtual std::optional<Entity> RenderFilter(
144+
const FilterInput::Vector& inputs,
145+
const ContentContext& renderer,
146+
const Entity& entity,
147+
const Matrix& effect_transform,
148+
const Rect& coverage,
149+
const std::optional<Rect>& coverage_hint) const = 0;
149150

150151
std::optional<Rect> GetLocalCoverage(const Entity& local_entity) const;
151152

152153
FilterInput::Vector inputs_;
153-
std::optional<Rect> coverage_crop_;
154154
Matrix effect_transform_;
155155

156156
FML_DISALLOW_COPY_AND_ASSIGN(FilterContents);

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,13 @@ std::optional<Entity> DirectionalGaussianBlurFilterContents::RenderFilter(
8686
const ContentContext& renderer,
8787
const Entity& entity,
8888
const Matrix& effect_transform,
89-
const Rect& coverage) const {
89+
const Rect& coverage,
90+
const std::optional<Rect>& coverage_hint) const {
9091
using VS = GaussianBlurAlphaDecalPipeline::VertexShader;
9192
using FS = GaussianBlurAlphaDecalPipeline::FragmentShader;
9293

94+
bool is_first_pass = !source_override_;
95+
9396
//----------------------------------------------------------------------------
9497
/// Handle inputs.
9598
///
@@ -98,10 +101,20 @@ std::optional<Entity> DirectionalGaussianBlurFilterContents::RenderFilter(
98101
return std::nullopt;
99102
}
100103

104+
auto radius = Radius{blur_sigma_}.radius;
105+
101106
// Input 0 snapshot.
102107

103-
auto input_snapshot =
104-
inputs[0]->GetSnapshot("GaussianBlur", renderer, entity);
108+
std::optional<Rect> expanded_coverage_hint;
109+
if (coverage_hint.has_value()) {
110+
auto r = Size(radius, radius).Abs();
111+
expanded_coverage_hint =
112+
is_first_pass ? Rect(coverage_hint.value().origin - r,
113+
Size(coverage_hint.value().size + r * 2))
114+
: coverage_hint;
115+
}
116+
auto input_snapshot = inputs[0]->GetSnapshot("GaussianBlur", renderer, entity,
117+
expanded_coverage_hint);
105118
if (!input_snapshot.has_value()) {
106119
return std::nullopt;
107120
}
@@ -112,8 +125,6 @@ std::optional<Entity> DirectionalGaussianBlurFilterContents::RenderFilter(
112125
entity.GetStencilDepth()); // No blur to render.
113126
}
114127

115-
auto radius = Radius{blur_sigma_}.radius;
116-
117128
auto transform = entity.GetTransformation() * effect_transform.Basis();
118129
auto transformed_blur_radius =
119130
transform.TransformDirection(blur_direction_ * radius);
@@ -146,11 +157,21 @@ std::optional<Entity> DirectionalGaussianBlurFilterContents::RenderFilter(
146157
pass_texture_rect.origin.x -= transformed_blur_radius_length;
147158
pass_texture_rect.size.width += transformed_blur_radius_length * 2;
148159

160+
// Crop the pass texture with the rotated coverage hint if one was given.
161+
if (expanded_coverage_hint.has_value()) {
162+
auto maybe_pass_texture_rect = pass_texture_rect.Intersection(
163+
expanded_coverage_hint->TransformBounds(texture_rotate));
164+
if (!maybe_pass_texture_rect.has_value()) {
165+
return std::nullopt;
166+
}
167+
pass_texture_rect = *maybe_pass_texture_rect;
168+
}
169+
149170
// Source override snapshot.
150171

151172
auto source = source_override_ ? source_override_ : inputs[0];
152-
auto source_snapshot =
153-
source->GetSnapshot("GaussianBlur(Override)", renderer, entity);
173+
auto source_snapshot = source->GetSnapshot("GaussianBlur(Override)", renderer,
174+
entity, GetCoverageHint());
154175
if (!source_snapshot.has_value()) {
155176
return std::nullopt;
156177
}
@@ -172,8 +193,9 @@ std::optional<Entity> DirectionalGaussianBlurFilterContents::RenderFilter(
172193
/// Render to texture.
173194
///
174195

175-
ContentContext::SubpassCallback callback = [&](const ContentContext& renderer,
176-
RenderPass& pass) {
196+
ContentContext::SubpassCallback subpass_callback = [&](const ContentContext&
197+
renderer,
198+
RenderPass& pass) {
177199
auto& host_buffer = pass.GetTransientsBuffer();
178200

179201
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
@@ -294,16 +316,16 @@ std::optional<Entity> DirectionalGaussianBlurFilterContents::RenderFilter(
294316
{
295317
scale.x = scale_curve(transformed_blur_radius_length);
296318

297-
Scalar y_radius = std::abs(pass_transform.GetDirectionScale(Vector2(
298-
0, source_override_ ? Radius{secondary_blur_sigma_}.radius : 1)));
319+
Scalar y_radius = std::abs(pass_transform.GetDirectionScale(
320+
Vector2(0, !is_first_pass ? Radius{secondary_blur_sigma_}.radius : 1)));
299321
scale.y = scale_curve(y_radius);
300322
}
301323

302324
Vector2 scaled_size = pass_texture_rect.size * scale;
303325
ISize floored_size = ISize(scaled_size.x, scaled_size.y);
304326

305327
auto out_texture = renderer.MakeSubpass("Directional Gaussian Blur Filter",
306-
floored_size, callback);
328+
floored_size, subpass_callback);
307329

308330
if (!out_texture) {
309331
return std::nullopt;
@@ -339,7 +361,7 @@ std::optional<Rect> DirectionalGaussianBlurFilterContents::GetFilterCoverage(
339361

340362
auto transform = inputs[0]->GetTransform(entity) * effect_transform.Basis();
341363
auto transformed_blur_vector =
342-
transform.TransformDirection(blur_direction_* Radius{blur_sigma_}.radius)
364+
transform.TransformDirection(blur_direction_ * Radius{blur_sigma_}.radius)
343365
.Abs();
344366
auto extent = coverage->size + transformed_blur_vector * 2;
345367
return Rect(coverage->origin - transformed_blur_vector,

impeller/entity/contents/filters/gaussian_blur_filter_contents.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents {
3737

3838
private:
3939
// |FilterContents|
40-
std::optional<Entity> RenderFilter(const FilterInput::Vector& input_textures,
41-
const ContentContext& renderer,
42-
const Entity& entity,
43-
const Matrix& effect_transform,
44-
const Rect& coverage) const override;
40+
std::optional<Entity> RenderFilter(
41+
const FilterInput::Vector& input_textures,
42+
const ContentContext& renderer,
43+
const Entity& entity,
44+
const Matrix& effect_transform,
45+
const Rect& coverage,
46+
const std::optional<Rect>& coverage_hint) const override;
4547
Sigma blur_sigma_;
4648
Sigma secondary_blur_sigma_;
4749
Vector2 blur_direction_;

impeller/entity/contents/filters/inputs/contents_filter_input.cc

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ FilterInput::Variant ContentsFilterInput::GetInput() const {
2424
std::optional<Snapshot> ContentsFilterInput::GetSnapshot(
2525
const std::string& label,
2626
const ContentContext& renderer,
27-
const Entity& entity) const {
27+
const Entity& entity,
28+
std::optional<Rect> coverage_limit) const {
2829
if (!snapshot_.has_value()) {
2930
snapshot_ = contents_->RenderToSnapshot(
30-
renderer, // renderer
31-
entity, // entity
32-
std::nullopt, // coverage_limit
33-
std::nullopt, // sampler_descriptor
34-
msaa_enabled_, // msaa_enabled
31+
renderer, // renderer
32+
entity, // entity
33+
coverage_limit, // coverage_limit
34+
std::nullopt, // sampler_descriptor
35+
msaa_enabled_, // msaa_enabled
3536
SPrintF("Contents to %s Filter Snapshot", label.c_str())); // label
3637
}
3738
return snapshot_;

0 commit comments

Comments
 (0)