Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2174,5 +2174,52 @@ TEST_P(AiksTest, CanRenderDestructiveSaveLayer) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CanRenderBackdropBlurInteractive) {
auto callback = [&](AiksContext& renderer, RenderTarget& render_target) {
auto [a, b] = IMPELLER_PLAYGROUND_LINE(Point(50, 50), Point(300, 200), 30,
Color::White(), Color::White());

Canvas canvas;
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
canvas.DrawCircle({300, 200}, 100, {.color = Color::GreenYellow()});
canvas.DrawCircle({140, 170}, 75, {.color = Color::DarkMagenta()});
canvas.DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
canvas.ClipRRect(Rect::MakeLTRB(a.x, a.y, b.x, b.y), 20);
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
[](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, Sigma(20.0), Sigma(20.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp, effect_transform);
});
canvas.Restore();

return renderer.Render(canvas.EndRecordingAsPicture(), render_target);
};

ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(AiksTest, CanRenderBackdropBlur) {
Canvas canvas;
canvas.DrawCircle({100, 100}, 50, {.color = Color::CornflowerBlue()});
canvas.DrawCircle({300, 200}, 100, {.color = Color::GreenYellow()});
canvas.DrawCircle({140, 170}, 75, {.color = Color::DarkMagenta()});
canvas.DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
canvas.ClipRRect(Rect::MakeLTRB(75, 50, 375, 275), 20);
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
[](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, Sigma(30.0), Sigma(30.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp, effect_transform);
});
canvas.Restore();

ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

} // namespace testing
} // namespace impeller
8 changes: 8 additions & 0 deletions impeller/entity/contents/contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ bool Contents::ShouldRender(const Entity& entity,
return stencil_coverage->IntersectsWithRect(coverage.value());
}

void Contents::SetCoverageHint(std::optional<Rect> coverage_hint) {
coverage_hint_ = coverage_hint;
}

const std::optional<Rect>& Contents::GetCoverageHint() const {
return coverage_hint_;
}

std::optional<Size> Contents::GetColorSourceSize() const {
return color_source_size_;
};
Expand Down
9 changes: 9 additions & 0 deletions impeller/entity/contents/contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ class Contents {
/// @brief Get the screen space bounding rectangle that this contents affects.
virtual std::optional<Rect> GetCoverage(const Entity& entity) const = 0;

/// @brief Hint that specifies the coverage area of this Contents that will
/// actually be used during rendering. This is for optimization
/// purposes only and can not be relied on as a clip. May optionally
/// affect the result of `GetCoverage()`.
void SetCoverageHint(std::optional<Rect> coverage_hint);

const std::optional<Rect>& GetCoverageHint() const;

/// @brief Whether this Contents only emits opaque source colors from the
/// fragment stage. This value does not account for any entity
/// properties (e.g. the blend mode), clips/visibility culling, or
Expand Down Expand Up @@ -110,6 +118,7 @@ class Contents {
virtual void SetInheritedOpacity(Scalar opacity);

private:
std::optional<Rect> coverage_hint_;
std::optional<Size> color_source_size_;

FML_DISALLOW_COPY_AND_ASSIGN(Contents);
Expand Down
3 changes: 2 additions & 1 deletion impeller/entity/contents/filters/blend_filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,8 @@ std::optional<Entity> BlendFilterContents::RenderFilter(
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage) const {
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const {
if (inputs.empty()) {
return std::nullopt;
}
Expand Down
12 changes: 7 additions & 5 deletions impeller/entity/contents/filters/blend_filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ class BlendFilterContents : public ColorFilterContents {

private:
// |FilterContents|
std::optional<Entity> RenderFilter(const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage) const override;
std::optional<Entity> RenderFilter(
const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const override;

/// @brief Optimized advanced blend that avoids a second subpass when there is
/// only a single input and a foreground color.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ std::optional<Entity> BorderMaskBlurFilterContents::RenderFilter(
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage) const {
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const {
using VS = BorderMaskBlurPipeline::VertexShader;
using FS = BorderMaskBlurPipeline::FragmentShader;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ class BorderMaskBlurFilterContents final : public FilterContents {

private:
// |FilterContents|
std::optional<Entity> RenderFilter(const FilterInput::Vector& input_textures,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage) const override;
std::optional<Entity> RenderFilter(
const FilterInput::Vector& input_textures,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const override;

Sigma sigma_x_;
Sigma sigma_y_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ std::optional<Entity> ColorMatrixFilterContents::RenderFilter(
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage) const {
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const {
using VS = ColorMatrixColorFilterPipeline::VertexShader;
using FS = ColorMatrixColorFilterPipeline::FragmentShader;

Expand Down
12 changes: 7 additions & 5 deletions impeller/entity/contents/filters/color_matrix_filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ class ColorMatrixFilterContents final : public ColorFilterContents {

private:
// |FilterContents|
std::optional<Entity> RenderFilter(const FilterInput::Vector& input_textures,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage) const override;
std::optional<Entity> RenderFilter(
const FilterInput::Vector& input_textures,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const override;

ColorMatrix matrix_;

Expand Down
23 changes: 11 additions & 12 deletions impeller/entity/contents/filters/filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,6 @@ void FilterContents::SetInputs(FilterInput::Vector inputs) {
inputs_ = std::move(inputs);
}

void FilterContents::SetCoverageCrop(std::optional<Rect> coverage_crop) {
coverage_crop_ = coverage_crop;
}

void FilterContents::SetEffectTransform(Matrix effect_transform) {
effect_transform_ = effect_transform;
}
Expand All @@ -171,7 +167,7 @@ bool FilterContents::Render(const ContentContext& renderer,

// Run the filter.

auto maybe_entity = GetEntity(renderer, entity);
auto maybe_entity = GetEntity(renderer, entity, GetCoverageHint());
if (!maybe_entity.has_value()) {
return true;
}
Expand All @@ -181,8 +177,8 @@ bool FilterContents::Render(const ContentContext& renderer,
std::optional<Rect> FilterContents::GetLocalCoverage(
const Entity& local_entity) const {
auto coverage = GetFilterCoverage(inputs_, local_entity, effect_transform_);
if (coverage_crop_.has_value() && coverage.has_value()) {
coverage = coverage->Intersection(coverage_crop_.value());
if (GetCoverageHint().has_value() && coverage.has_value()) {
coverage = coverage->Intersection(*GetCoverageHint());
}

return coverage;
Expand Down Expand Up @@ -223,8 +219,10 @@ std::optional<Rect> FilterContents::GetFilterCoverage(
return result;
}

std::optional<Entity> FilterContents::GetEntity(const ContentContext& renderer,
const Entity& entity) const {
std::optional<Entity> FilterContents::GetEntity(
const ContentContext& renderer,
const Entity& entity,
const std::optional<Rect>& coverage_hint) const {
Entity entity_with_local_transform = entity;
entity_with_local_transform.SetTransformation(
GetTransform(entity.GetTransformation()));
Expand All @@ -235,7 +233,7 @@ std::optional<Entity> FilterContents::GetEntity(const ContentContext& renderer,
}

return RenderFilter(inputs_, renderer, entity_with_local_transform,
effect_transform_, coverage.value());
effect_transform_, coverage.value(), coverage_hint);
}

std::optional<Snapshot> FilterContents::RenderToSnapshot(
Expand All @@ -247,12 +245,13 @@ std::optional<Snapshot> FilterContents::RenderToSnapshot(
const std::string& label) const {
// Resolve the render instruction (entity) from the filter and render it to a
// snapshot.
if (std::optional<Entity> result = GetEntity(renderer, entity);
if (std::optional<Entity> result =
GetEntity(renderer, entity, coverage_limit);
result.has_value()) {
return result->GetContents()->RenderToSnapshot(
renderer, // renderer
result.value(), // entity
std::nullopt, // coverage_limit
coverage_limit, // coverage_limit
std::nullopt, // sampler_descriptor
true, // msaa_enabled
label); // label
Expand Down
22 changes: 11 additions & 11 deletions impeller/entity/contents/filters/filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,15 @@ class FilterContents : public Contents {
/// particular filter's implementation.
void SetInputs(FilterInput::Vector inputs);

/// @brief Screen space bounds to use for cropping the filter output.
void SetCoverageCrop(std::optional<Rect> coverage_crop);

/// @brief Sets the transform which gets appended to the effect of this
/// filter. Note that this is in addition to the entity's transform.
void SetEffectTransform(Matrix effect_transform);

/// @brief Create an Entity that renders this filter's output.
std::optional<Entity> GetEntity(const ContentContext& renderer,
const Entity& entity) const;
std::optional<Entity> GetEntity(
const ContentContext& renderer,
const Entity& entity,
const std::optional<Rect>& coverage_hint) const;

// |Contents|
bool Render(const ContentContext& renderer,
Expand Down Expand Up @@ -141,16 +140,17 @@ class FilterContents : public Contents {
const Matrix& effect_transform) const;

/// @brief Converts zero or more filter inputs into a render instruction.
virtual std::optional<Entity> RenderFilter(const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage) const = 0;
virtual std::optional<Entity> RenderFilter(
const FilterInput::Vector& inputs,
const ContentContext& renderer,
const Entity& entity,
const Matrix& effect_transform,
const Rect& coverage,
const std::optional<Rect>& coverage_hint) const = 0;

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

FilterInput::Vector inputs_;
std::optional<Rect> coverage_crop_;
Matrix effect_transform_;

FML_DISALLOW_COPY_AND_ASSIGN(FilterContents);
Expand Down
Loading