blob: 6bce41f2acfc76b5c2f4a3c09835f3a1f0acfe5b [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/entity/contents/filters/matrix_filter_contents.h"
namespace impeller {
MatrixFilterContents::MatrixFilterContents() = default;
MatrixFilterContents::~MatrixFilterContents() = default;
void MatrixFilterContents::SetMatrix(Matrix matrix) {
matrix_ = matrix;
}
void MatrixFilterContents::SetRenderingMode(
Entity::RenderingMode rendering_mode) {
rendering_mode_ = rendering_mode;
FilterContents::SetRenderingMode(rendering_mode);
}
bool MatrixFilterContents::IsTranslationOnly() const {
return matrix_.Basis().IsIdentity() && FilterContents::IsTranslationOnly();
}
void MatrixFilterContents::SetSamplerDescriptor(SamplerDescriptor desc) {
sampler_descriptor_ = std::move(desc);
}
std::optional<Entity> MatrixFilterContents::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 {
auto snapshot = inputs[0]->GetSnapshot("Matrix", renderer, entity);
if (!snapshot.has_value()) {
return std::nullopt;
}
// The filter's matrix needs to be applied within the space defined by the
// scene's current transform matrix (CTM). For example: If the CTM is
// scaled up, then translations applied by the matrix should be magnified
// accordingly.
//
// To accomplish this, we sandwich the filter's matrix within the CTM in both
// cases. But notice that for the subpass backdrop filter case, we use the
// "effect transform" instead of the Entity's transform!
//
// That's because in the subpass backdrop filter case, the Entity's transform
// isn't actually the captured CTM of the scene like it usually is; instead,
// it's just a screen space translation that offsets the backdrop texture (as
// mentioned above). And so we sneak the subpass's captured CTM in through the
// effect transform.
auto transform = rendering_mode_ == Entity::RenderingMode::kSubpass
? effect_transform
: entity.GetTransform();
snapshot->transform = transform * //
matrix_ * //
transform.Invert() * //
snapshot->transform;
snapshot->sampler_descriptor = sampler_descriptor_;
return Entity::FromSnapshot(snapshot, entity.GetBlendMode(),
entity.GetClipDepth());
}
std::optional<Rect> MatrixFilterContents::GetFilterSourceCoverage(
const Matrix& effect_transform,
const Rect& output_limit) const {
auto transform = effect_transform * //
matrix_ * //
effect_transform.Invert(); //
if (transform.GetDeterminant() == 0.0) {
return std::nullopt;
}
auto inverse = transform.Invert();
return output_limit.TransformBounds(inverse);
}
std::optional<Rect> MatrixFilterContents::GetFilterCoverage(
const FilterInput::Vector& inputs,
const Entity& entity,
const Matrix& effect_transform) const {
if (inputs.empty()) {
return std::nullopt;
}
auto coverage = inputs[0]->GetCoverage(entity);
if (!coverage.has_value()) {
return std::nullopt;
}
auto& m = rendering_mode_ == Entity::RenderingMode::kSubpass
? effect_transform
: inputs[0]->GetTransform(entity);
auto transform = m * //
matrix_ * //
m.Invert(); //
return coverage->TransformBounds(transform);
}
} // namespace impeller