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

[Impeller] Incorporate filters in subpass coverage. #45778

Merged
merged 2 commits into from
Sep 14, 2023
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
4 changes: 2 additions & 2 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3173,7 +3173,7 @@ TEST_P(AiksTest, MatrixSaveLayerFilter) {
canvas.SaveLayer({.image_filter = ImageFilter::MakeMatrix(
Matrix::MakeTranslation(Vector2(1, 1) *
(200 + 100 * k1OverSqrt2)) *
Matrix::MakeScale(Vector2(1, 1) * 0.2) *
Matrix::MakeScale(Vector2(1, 1) * 0.5) *
Matrix::MakeTranslation(Vector2(-200, -200)),
SamplerDescriptor{})},
std::nullopt);
Expand Down Expand Up @@ -3201,7 +3201,7 @@ TEST_P(AiksTest, MatrixBackdropFilter) {
{}, std::nullopt,
ImageFilter::MakeMatrix(
Matrix::MakeTranslation(Vector2(1, 1) * (100 + 100 * k1OverSqrt2)) *
Matrix::MakeScale(Vector2(1, 1) * 0.2) *
Matrix::MakeScale(Vector2(1, 1) * 0.5) *
Matrix::MakeTranslation(Vector2(-100, -100)),
SamplerDescriptor{}));
canvas.Restore();
Expand Down
17 changes: 12 additions & 5 deletions impeller/aiks/paint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,21 @@ std::shared_ptr<Contents> Paint::WithFilters(
std::shared_ptr<Contents> input) const {
input = WithColorFilter(input, /*absorb_opacity=*/true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dry by comment on an unrelated item: Instead of booleans for absorb_opacity and is_subpass, I'd rather have a typed enum with AbsorbOpacity::kYes and AbsorbOpacity::kNo and the like.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an issue about this: flutter/flutter#134681

input = WithInvertFilter(input);
input = WithImageFilter(input, Matrix(), /*is_subpass=*/false);
auto image_filter = WithImageFilter(input, Matrix(), /*is_subpass=*/false);
if (image_filter) {
input = image_filter;
}
return input;
}

std::shared_ptr<Contents> Paint::WithFiltersForSubpassTarget(
std::shared_ptr<Contents> input,
const Matrix& effect_transform) const {
input = WithImageFilter(input, effect_transform, /*is_subpass=*/true);
auto image_filter =
WithImageFilter(input, effect_transform, /*is_subpass=*/true);
if (image_filter) {
input = image_filter;
}
input = WithColorFilter(input, /*absorb_opacity=*/true);
return input;
}
Expand All @@ -81,12 +88,12 @@ std::shared_ptr<Contents> Paint::WithMaskBlur(std::shared_ptr<Contents> input,
return input;
}

std::shared_ptr<Contents> Paint::WithImageFilter(
std::shared_ptr<Contents> input,
std::shared_ptr<FilterContents> Paint::WithImageFilter(
const FilterInput::Variant& input,
const Matrix& effect_transform,
bool is_subpass) const {
if (!image_filter) {
return input;
return nullptr;
}
auto filter = image_filter->WrapInput(FilterInput::Make(input));
filter->SetIsForSubpass(is_subpass);
Expand Down
9 changes: 5 additions & 4 deletions impeller/aiks/paint.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,12 @@ struct Paint {
std::shared_ptr<Contents> WithMaskBlur(std::shared_ptr<Contents> input,
bool is_solid_color) const;

private:
std::shared_ptr<Contents> WithImageFilter(std::shared_ptr<Contents> input,
const Matrix& effect_transform,
bool is_subpass) const;
std::shared_ptr<FilterContents> WithImageFilter(
const FilterInput::Variant& input,
const Matrix& effect_transform,
bool is_subpass) const;

private:
std::shared_ptr<Contents> WithColorFilter(std::shared_ptr<Contents> input,
bool absorb_opacity = false) const;

Expand Down
14 changes: 14 additions & 0 deletions impeller/aiks/paint_pass_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ std::shared_ptr<Contents> PaintPassDelegate::CreateContentsForSubpassTarget(
effect_transform);
}

// |EntityPassDelgate|
std::shared_ptr<FilterContents> PaintPassDelegate::WithImageFilter(
const FilterInput::Variant& input,
const Matrix& effect_transform) const {
return paint_.WithImageFilter(input, effect_transform, true);
}

/// OpacityPeepholePassDelegate
/// ----------------------------------------------

Expand Down Expand Up @@ -140,4 +147,11 @@ OpacityPeepholePassDelegate::CreateContentsForSubpassTarget(
effect_transform);
}

// |EntityPassDelgate|
std::shared_ptr<FilterContents> OpacityPeepholePassDelegate::WithImageFilter(
const FilterInput::Variant& input,
const Matrix& effect_transform) const {
return paint_.WithImageFilter(input, effect_transform, true);
}

} // namespace impeller
10 changes: 10 additions & 0 deletions impeller/aiks/paint_pass_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ class PaintPassDelegate final : public EntityPassDelegate {
std::shared_ptr<Texture> target,
const Matrix& effect_transform) override;

// |EntityPassDelgate|
std::shared_ptr<FilterContents> WithImageFilter(
const FilterInput::Variant& input,
const Matrix& effect_transform) const override;

private:
const Paint paint_;

Expand Down Expand Up @@ -61,6 +66,11 @@ class OpacityPeepholePassDelegate final : public EntityPassDelegate {
std::shared_ptr<Texture> target,
const Matrix& effect_transform) override;

// |EntityPassDelgate|
std::shared_ptr<FilterContents> WithImageFilter(
const FilterInput::Variant& input,
const Matrix& effect_transform) const override;

private:
const Paint paint_;

Expand Down
4 changes: 4 additions & 0 deletions impeller/entity/contents/contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ std::optional<Color> Contents::AsBackgroundColor(const Entity& entity,
return {};
}

const FilterContents* Contents::AsFilter() const {
return nullptr;
}

bool Contents::ApplyColorFilter(
const Contents::ColorFilterProc& color_filter_proc) {
return false;
Expand Down
7 changes: 7 additions & 0 deletions impeller/entity/contents/contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct ContentContextOptions;
class Entity;
class Surface;
class RenderPass;
class FilterContents;

ContentContextOptions OptionsFromPass(const RenderPass& pass);

Expand Down Expand Up @@ -155,6 +156,12 @@ class Contents {
virtual std::optional<Color> AsBackgroundColor(const Entity& entity,
ISize target_size) const;

//----------------------------------------------------------------------------
/// @brief Cast to a filter. Returns `nullptr` if this Contents is not a
/// filter.
///
virtual const FilterContents* AsFilter() const;

//----------------------------------------------------------------------------
/// @brief If possible, applies a color filter to this contents inputs on
/// the CPU.
Expand Down
12 changes: 12 additions & 0 deletions impeller/entity/contents/filters/filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,25 @@ std::optional<Snapshot> FilterContents::RenderToSnapshot(
return std::nullopt;
}

const FilterContents* FilterContents::AsFilter() const {
return this;
}

Matrix FilterContents::GetLocalTransform(const Matrix& parent_transform) const {
return Matrix();
}

Matrix FilterContents::GetTransform(const Matrix& parent_transform) const {
return parent_transform * GetLocalTransform(parent_transform);
}
bool FilterContents::IsTranslationOnly() const {
for (auto& input : inputs_) {
if (!input->IsTranslationOnly()) {
return false;
}
}
return true;
}

bool FilterContents::IsLeaf() const {
for (auto& input : inputs_) {
Expand Down
13 changes: 13 additions & 0 deletions impeller/entity/contents/filters/filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,23 @@ class FilterContents : public Contents {
bool msaa_enabled = true,
const std::string& label = "Filter Snapshot") const override;

// |Contents|
const FilterContents* AsFilter() const override;

virtual Matrix GetLocalTransform(const Matrix& parent_transform) const;

Matrix GetTransform(const Matrix& parent_transform) const;

/// @brief Returns true if this filter graph doesn't perform any basis
/// transformations to the filtered content. For example: Rotating,
/// scaling, and skewing are all basis transformations, but
/// translating is not.
///
/// This is useful for determining whether a filtered object's space
/// is compatible enough with the parent pass space to perform certain
/// subpass clipping optimizations.
virtual bool IsTranslationOnly() const;

/// @brief Returns `true` if this filter does not have any `FilterInput`
/// children.
bool IsLeaf() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ void FilterContentsFilterInput::PopulateGlyphAtlas(
filter_->PopulateGlyphAtlas(lazy_glyph_atlas, scale);
}

bool FilterContentsFilterInput::IsTranslationOnly() const {
return filter_->IsTranslationOnly();
}

bool FilterContentsFilterInput::IsLeaf() const {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class FilterContentsFilterInput final : public FilterInput {
const std::shared_ptr<LazyGlyphAtlas>& lazy_glyph_atlas,
Scalar scale) override;

// |FilterInput|
bool IsTranslationOnly() const override;

// |FilterInput|
bool IsLeaf() const override;

Expand Down
4 changes: 4 additions & 0 deletions impeller/entity/contents/filters/inputs/filter_input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ void FilterInput::PopulateGlyphAtlas(

FilterInput::~FilterInput() = default;

bool FilterInput::IsTranslationOnly() const {
return true;
}

bool FilterInput::IsLeaf() const {
return true;
}
Expand Down
3 changes: 3 additions & 0 deletions impeller/entity/contents/filters/inputs/filter_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ class FilterInput {
const std::shared_ptr<LazyGlyphAtlas>& lazy_glyph_atlas,
Scalar scale);

/// @see `FilterContents::HasBasisTransformations`
virtual bool IsTranslationOnly() const;

/// @brief Returns `true` unless this input is a `FilterInput`, which may
/// take other inputs.
virtual bool IsLeaf() const;
Expand Down
4 changes: 4 additions & 0 deletions impeller/entity/contents/filters/matrix_filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ void MatrixFilterContents::SetIsForSubpass(bool is_subpass) {
FilterContents::SetIsForSubpass(is_subpass);
}

bool MatrixFilterContents::IsTranslationOnly() const {
return matrix_.Basis().IsIdentity() && FilterContents::IsTranslationOnly();
}

void MatrixFilterContents::SetSamplerDescriptor(SamplerDescriptor desc) {
sampler_descriptor_ = std::move(desc);
}
Expand Down
3 changes: 3 additions & 0 deletions impeller/entity/contents/filters/matrix_filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class MatrixFilterContents final : public FilterContents {
// |FilterContents|
void SetIsForSubpass(bool is_for_subpass) override;

// |FilterContents|
bool IsTranslationOnly() const override;

void SetSamplerDescriptor(SamplerDescriptor desc);

// |FilterContents|
Expand Down
43 changes: 40 additions & 3 deletions impeller/entity/entity_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,39 @@ std::optional<Rect> EntityPass::GetElementsCoverage(
if (auto entity = std::get_if<Entity>(&element)) {
coverage = entity->GetCoverage();

// When the coverage limit is std::nullopt, that means there is no limit,
// as opposed to empty coverage.
if (coverage.has_value() && coverage_limit.has_value()) {
coverage = coverage->Intersection(coverage_limit.value());
const auto* filter = entity->GetContents()->AsFilter();
if (!filter || filter->IsTranslationOnly()) {
coverage = coverage->Intersection(coverage_limit.value());
}
}
} else if (auto subpass =
} else if (auto subpass_ptr =
std::get_if<std::unique_ptr<EntityPass>>(&element)) {
coverage = GetSubpassCoverage(*subpass->get(), coverage_limit);
auto& subpass = *subpass_ptr->get();

std::optional<Rect> unfiltered_coverage =
GetSubpassCoverage(subpass, std::nullopt);
if (!unfiltered_coverage.has_value()) {
continue;
}

std::shared_ptr<FilterContents> image_filter =
subpass.delegate_->WithImageFilter(*unfiltered_coverage,
subpass.xformation_);
if (image_filter) {
Entity subpass_entity;
subpass_entity.SetTransformation(subpass.xformation_);
coverage = image_filter->GetCoverage(subpass_entity);
} else {
coverage = unfiltered_coverage;
}

if (coverage.has_value() && coverage_limit.has_value() &&
(!image_filter || image_filter->IsTranslationOnly())) {
coverage = coverage->Intersection(coverage_limit.value());
}
} else {
FML_UNREACHABLE();
}
Expand All @@ -135,6 +162,16 @@ std::optional<Rect> EntityPass::GetElementsCoverage(
std::optional<Rect> EntityPass::GetSubpassCoverage(
const EntityPass& subpass,
std::optional<Rect> coverage_limit) const {
std::shared_ptr<FilterContents> image_filter =
subpass.delegate_->WithImageFilter(Rect(), subpass.xformation_);

// If the filter graph transforms the basis of the subpass, then its space
// has deviated too much from the parent pass to safely intersect with the
// pass coverage limit.
coverage_limit =
(image_filter && image_filter->IsTranslationOnly() ? std::nullopt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be !IsTranslationOnly()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah

: coverage_limit);

auto entities_coverage = subpass.GetElementsCoverage(coverage_limit);
// The entities don't cover anything. There is nothing to do.
if (!entities_coverage.has_value()) {
Expand Down
3 changes: 3 additions & 0 deletions impeller/entity/entity_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ class EntityPass {

void SetEnableOffscreenCheckerboard(bool enabled);

//----------------------------------------------------------------------------
/// @brief Get the coverage of an unfiltered subpass.
///
std::optional<Rect> GetSubpassCoverage(
const EntityPass& subpass,
std::optional<Rect> coverage_limit) const;
Expand Down
7 changes: 7 additions & 0 deletions impeller/entity/entity_pass_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ class DefaultEntityPassDelegate final : public EntityPassDelegate {
FML_UNREACHABLE();
}

// |EntityPassDelgate|
std::shared_ptr<FilterContents> WithImageFilter(
const FilterInput::Variant& input,
const Matrix& effect_transform) const override {
return nullptr;
}

private:
FML_DISALLOW_COPY_AND_ASSIGN(DefaultEntityPassDelegate);
};
Expand Down
6 changes: 6 additions & 0 deletions impeller/entity/entity_pass_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "flutter/fml/macros.h"
#include "impeller/core/texture.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/entity/contents/filters/inputs/filter_input.h"

namespace impeller {

Expand All @@ -32,6 +34,10 @@ class EntityPassDelegate {
std::shared_ptr<Texture> target,
const Matrix& effect_transform) = 0;

virtual std::shared_ptr<FilterContents> WithImageFilter(
const FilterInput::Variant& input,
const Matrix& effect_transform) const = 0;

private:
FML_DISALLOW_COPY_AND_ASSIGN(EntityPassDelegate);
};
Expand Down
7 changes: 7 additions & 0 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ class TestPassDelegate final : public EntityPassDelegate {
return nullptr;
}

// |EntityPassDelegate|
std::shared_ptr<FilterContents> WithImageFilter(
const FilterInput::Variant& input,
const Matrix& effect_transform) const override {
return nullptr;
}

private:
const std::optional<Rect> coverage_;
const bool collapse_;
Expand Down