Flutter Impeller
matrix_filter_contents.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 namespace impeller {
8 
10 
12 
14  matrix_ = matrix;
15 }
16 
18  Entity::RenderingMode rendering_mode) {
19  rendering_mode_ = rendering_mode;
20  FilterContents::SetRenderingMode(rendering_mode);
21 }
22 
24  sampler_descriptor_ = desc;
25 }
26 
27 namespace {
28 Matrix CalculateSubpassTransform(const Matrix& snapshot_transform,
29  const Matrix& effect_transform,
30  const Matrix& matrix,
31  Entity::RenderingMode rendering_mode) {
32  if (rendering_mode ==
34  return snapshot_transform * //
35  effect_transform * //
36  matrix * //
37  effect_transform.Invert();
38  } else {
39  FML_DCHECK(rendering_mode ==
41  return effect_transform * //
42  matrix * //
43  effect_transform.Invert() * //
44  snapshot_transform;
45  }
46 }
47 } // namespace
48 
49 std::optional<Entity> MatrixFilterContents::RenderFilter(
50  const FilterInput::Vector& inputs,
51  const ContentContext& renderer,
52  const Entity& entity,
53  const Matrix& effect_transform,
54  const Rect& coverage,
55  const std::optional<Rect>& coverage_hint) const {
56  auto snapshot = inputs[0]->GetSnapshot("Matrix", renderer, entity);
57  if (!snapshot.has_value()) {
58  return std::nullopt;
59  }
60 
61  if (rendering_mode_ ==
63  rendering_mode_ ==
65  // There are two special quirks with how Matrix filters behave when used as
66  // subpass backdrop filters:
67  //
68  // 1. For subpass backdrop filters, the snapshot transform is always just a
69  // translation that positions the parent pass texture correctly relative
70  // to the subpass texture. However, this translation always needs to be
71  // applied in screen space.
72  //
73  // Since we know the snapshot transform will always have an identity
74  // basis in this case, we safely reverse the order and apply the filter's
75  // matrix within the snapshot transform space.
76  //
77  // 2. The filter's matrix needs to be applied within the space defined by
78  // the scene's current transformation matrix (CTM). For example: If the
79  // CTM is scaled up, then translations applied by the matrix should be
80  // magnified accordingly.
81  //
82  // To accomplish this, we sandwitch the filter's matrix within the CTM in
83  // both cases. But notice that for the subpass backdrop filter case, we
84  // use the "effect transform" instead of the Entity's transform!
85  //
86  // That's because in the subpass backdrop filter case, the Entity's
87  // transform isn't actually the captured CTM of the scene like it usually
88  // is; instead, it's just a screen space translation that offsets the
89  // backdrop texture (as mentioned above). And so we sneak the subpass's
90  // captured CTM in through the effect transform.
91  //
92  snapshot->transform = CalculateSubpassTransform(
93  snapshot->transform, effect_transform, matrix_, rendering_mode_);
94  } else {
95  snapshot->transform = entity.GetTransform() * //
96  matrix_ * //
97  entity.GetTransform().Invert() * //
98  snapshot->transform;
99  }
100  snapshot->sampler_descriptor = sampler_descriptor_;
101  if (!snapshot.has_value()) {
102  return std::nullopt;
103  }
104  return Entity::FromSnapshot(snapshot.value(), entity.GetBlendMode());
105 }
106 
107 std::optional<Rect> MatrixFilterContents::GetFilterSourceCoverage(
108  const Matrix& effect_transform,
109  const Rect& output_limit) const {
110  auto transform = effect_transform * //
111  matrix_ * //
112  effect_transform.Invert(); //
113  if (!transform.IsInvertible()) {
114  return std::nullopt;
115  }
116  auto inverse = transform.Invert();
117  return output_limit.TransformBounds(inverse);
118 }
119 
121  const FilterInput::Vector& inputs,
122  const Entity& entity,
123  const Matrix& effect_transform) const {
124  if (inputs.empty()) {
125  return std::nullopt;
126  }
127 
128  std::optional<Rect> coverage = inputs[0]->GetCoverage(entity);
129  if (!coverage.has_value()) {
130  return std::nullopt;
131  }
132 
133  Matrix input_transform = inputs[0]->GetTransform(entity);
134  if (rendering_mode_ ==
136  rendering_mode_ ==
138  Rect coverage_bounds = coverage->TransformBounds(input_transform.Invert());
139  Matrix transform = CalculateSubpassTransform(
140  input_transform, effect_transform, matrix_, rendering_mode_);
141  return coverage_bounds.TransformBounds(transform);
142  } else {
143  Matrix transform = input_transform * //
144  matrix_ * //
145  input_transform.Invert(); //
146  return coverage->TransformBounds(transform);
147  }
148 }
149 
150 } // namespace impeller
static Entity FromSnapshot(const Snapshot &snapshot, BlendMode blend_mode=BlendMode::kSrcOver)
Create an entity that can be used to render a given snapshot.
Definition: entity.cc:18
virtual void SetRenderingMode(Entity::RenderingMode rendering_mode)
Marks this filter chain as applying in a subpass scenario.
std::vector< FilterInput::Ref > Vector
Definition: filter_input.h:33
std::optional< Rect > GetFilterCoverage(const FilterInput::Vector &inputs, const Entity &entity, const Matrix &effect_transform) const override
Internal utility method for |GetLocalCoverage| that computes the output coverage of this filter acros...
void SetRenderingMode(Entity::RenderingMode rendering_mode) override
Marks this filter chain as applying in a subpass scenario.
void SetSamplerDescriptor(const SamplerDescriptor &desc)
TRect< Scalar > Rect
Definition: rect.h:792
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
Matrix Invert() const
Definition: matrix.cc:97
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:476