mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Minimally crop advanced blends in EntityPass (flutter/engine#34347)
This commit is contained in:
parent
2a7cb615dd
commit
4f1ca4a7fb
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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()));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user