[Impeller] Minimally crop advanced blends in EntityPass (flutter/engine#34347)

This commit is contained in:
Brandon DeRosier 2022-06-28 00:44:04 -07:00 committed by GitHub
parent 2a7cb615dd
commit 4f1ca4a7fb
5 changed files with 62 additions and 14 deletions

View File

@ -116,6 +116,10 @@ void FilterContents::SetInputs(FilterInput::Vector inputs) {
inputs_ = std::move(inputs);
}
void FilterContents::SetCoverageCrop(std::optional<Rect> coverage_crop) {
coverage_crop_ = coverage_crop;
}
bool FilterContents::Render(const ContentContext& renderer,
const Entity& entity,
RenderPass& pass) const {
@ -146,11 +150,22 @@ bool FilterContents::Render(const ContentContext& renderer,
return contents->Render(renderer, e, pass);
}
std::optional<Rect> FilterContents::GetLocalCoverage(
const Entity& local_entity) const {
auto coverage = GetFilterCoverage(inputs_, local_entity);
if (coverage_crop_.has_value() && coverage.has_value()) {
coverage = coverage->Intersection(coverage_crop_.value());
}
return coverage;
}
std::optional<Rect> FilterContents::GetCoverage(const Entity& entity) const {
Entity entity_with_local_transform = entity;
entity_with_local_transform.SetTransformation(
GetTransform(entity.GetTransformation()));
return GetFilterCoverage(inputs_, entity_with_local_transform);
return GetLocalCoverage(entity_with_local_transform);
}
std::optional<Rect> FilterContents::GetFilterCoverage(
@ -186,7 +201,7 @@ std::optional<Snapshot> FilterContents::RenderToSnapshot(
entity_with_local_transform.SetTransformation(
GetTransform(entity.GetTransformation()));
auto coverage = GetFilterCoverage(inputs_, entity_with_local_transform);
auto coverage = GetLocalCoverage(entity_with_local_transform);
if (!coverage.has_value() || coverage->IsEmpty()) {
return std::nullopt;
}

View File

@ -109,13 +109,16 @@ class FilterContents : public Contents {
~FilterContents() override;
/// @brief The input texture sources for this filter. Each input's emitted
/// texture is expected to have premultiplied alpha colors.
/// @brief The input texture sources for this filter. Each input's emitted
/// texture is expected to have premultiplied alpha colors.
///
/// The number of required or optional textures depends on the
/// particular filter's implementation.
/// The number of required or optional textures depends on the
/// 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);
// |Contents|
bool Render(const ContentContext& renderer,
const Entity& entity,
@ -145,7 +148,10 @@ class FilterContents : public Contents {
RenderPass& pass,
const Rect& coverage) const = 0;
std::optional<Rect> GetLocalCoverage(const Entity& local_entity) const;
FilterInput::Vector inputs_;
std::optional<Rect> coverage_crop_;
FML_DISALLOW_COPY_AND_ASSIGN(FilterContents);
};

View File

@ -65,7 +65,7 @@ const std::shared_ptr<LazyGlyphAtlas>& EntityPass::GetLazyGlyphAtlas() const {
}
std::optional<Rect> EntityPass::GetElementsCoverage(
std::optional<Rect> coverage_clip) const {
std::optional<Rect> coverage_crop) const {
std::optional<Rect> result;
for (const auto& element : elements_) {
std::optional<Rect> coverage;
@ -73,12 +73,12 @@ std::optional<Rect> EntityPass::GetElementsCoverage(
if (auto entity = std::get_if<Entity>(&element)) {
coverage = entity->GetCoverage();
if (coverage.has_value() && coverage_clip.has_value()) {
coverage = coverage->Intersection(coverage_clip.value());
if (coverage.has_value() && coverage_crop.has_value()) {
coverage = coverage->Intersection(coverage_crop.value());
}
} else if (auto subpass =
std::get_if<std::unique_ptr<EntityPass>>(&element)) {
coverage = GetSubpassCoverage(*subpass->get(), coverage_clip);
coverage = GetSubpassCoverage(*subpass->get(), coverage_crop);
} else {
FML_UNREACHABLE();
}
@ -427,8 +427,10 @@ bool EntityPass::OnRender(ContentContext& renderer,
FilterInput::Make(result.entity.GetContents()),
FilterInput::Make(texture,
result.entity.GetTransformation().Invert())};
result.entity.SetContents(
FilterContents::MakeBlend(result.entity.GetBlendMode(), inputs));
auto contents =
FilterContents::MakeBlend(result.entity.GetBlendMode(), inputs);
contents->SetCoverageCrop(result.entity.GetCoverage());
result.entity.SetContents(std::move(contents));
result.entity.SetBlendMode(Entity::BlendMode::kSourceOver);
}

View File

@ -62,10 +62,10 @@ class EntityPass {
std::optional<Rect> GetSubpassCoverage(
const EntityPass& subpass,
std::optional<Rect> coverage_clip) const;
std::optional<Rect> coverage_crop) const;
std::optional<Rect> GetElementsCoverage(
std::optional<Rect> coverage_clip) const;
std::optional<Rect> coverage_crop) const;
private:
struct EntityResult {

View File

@ -131,6 +131,31 @@ TEST_P(EntityTest, EntityPassCoverageRespectsCoverageLimit) {
}
}
TEST_P(EntityTest, FilterCoverageRespectsCropRect) {
auto image = CreateTextureForFixture("boston.jpg");
auto filter = FilterContents::MakeBlend(Entity::BlendMode::kSoftLight,
FilterInput::Make({image}));
// Without the crop rect (default behavior).
{
auto actual = filter->GetCoverage({});
auto expected = Rect::MakeSize(Size(image->GetSize()));
ASSERT_TRUE(actual.has_value());
ASSERT_RECT_NEAR(actual.value(), expected);
}
// With the crop rect.
{
auto expected = Rect::MakeLTRB(50, 50, 100, 100);
filter->SetCoverageCrop(expected);
auto actual = filter->GetCoverage({});
ASSERT_TRUE(actual.has_value());
ASSERT_RECT_NEAR(actual.value(), expected);
}
}
TEST_P(EntityTest, CanDrawRect) {
Entity entity;
entity.SetTransformation(Matrix::MakeScale(GetContentScale()));