@@ -28,6 +28,26 @@ void MatrixFilterContents::SetSamplerDescriptor(SamplerDescriptor desc) {
2828 sampler_descriptor_ = std::move (desc);
2929}
3030
31+ namespace {
32+ Matrix CalculateSubpassTransform (const Matrix& snapshot_transform,
33+ const Matrix& effect_transform,
34+ const Matrix& matrix,
35+ Entity::RenderingMode rendering_mode) {
36+ if (rendering_mode == Entity::RenderingMode::kBackdropSubpass ) {
37+ return snapshot_transform * //
38+ effect_transform * //
39+ matrix * //
40+ effect_transform.Invert ();
41+ } else {
42+ FML_DCHECK (rendering_mode == Entity::RenderingMode::kImageFilterSubpass );
43+ return effect_transform * //
44+ matrix * //
45+ effect_transform.Invert () * //
46+ snapshot_transform;
47+ }
48+ }
49+ } // namespace
50+
3151std::optional<Entity> MatrixFilterContents::RenderFilter (
3252 const FilterInput::Vector& inputs,
3353 const ContentContext& renderer,
@@ -40,29 +60,43 @@ std::optional<Entity> MatrixFilterContents::RenderFilter(
4060 return std::nullopt ;
4161 }
4262
43- // The filter's matrix needs to be applied within the space defined by the
44- // scene's current transform matrix (CTM). For example: If the CTM is
45- // scaled up, then translations applied by the matrix should be magnified
46- // accordingly.
47- //
48- // To accomplish this, we sandwich the filter's matrix within the CTM in both
49- // cases. But notice that for the subpass backdrop filter case, we use the
50- // "effect transform" instead of the Entity's transform!
51- //
52- // That's because in the subpass backdrop filter case, the Entity's transform
53- // isn't actually the captured CTM of the scene like it usually is; instead,
54- // it's just a screen space translation that offsets the backdrop texture (as
55- // mentioned above). And so we sneak the subpass's captured CTM in through the
56- // effect transform.
57-
58- auto transform = rendering_mode_ == Entity::RenderingMode::kSubpass
59- ? effect_transform
60- : entity.GetTransform ();
61- snapshot->transform = transform * //
62- matrix_ * //
63- transform.Invert () * //
64- snapshot->transform ;
65-
63+ if (rendering_mode_ == Entity::RenderingMode::kImageFilterSubpass ||
64+ rendering_mode_ == Entity::RenderingMode::kBackdropSubpass ) {
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+ }
66100 snapshot->sampler_descriptor = sampler_descriptor_;
67101 if (!snapshot.has_value ()) {
68102 return std::nullopt ;
@@ -91,17 +125,24 @@ std::optional<Rect> MatrixFilterContents::GetFilterCoverage(
91125 return std::nullopt ;
92126 }
93127
94- auto coverage = inputs[0 ]->GetCoverage (entity);
128+ std::optional<Rect> coverage = inputs[0 ]->GetCoverage (entity);
95129 if (!coverage.has_value ()) {
96130 return std::nullopt ;
97131 }
98- auto & m = rendering_mode_ == Entity::RenderingMode::kSubpass
99- ? effect_transform
100- : inputs[0 ]->GetTransform (entity);
101- auto transform = m * //
102- matrix_ * //
103- m.Invert (); //
104- return coverage->TransformBounds (transform);
132+
133+ Matrix input_transform = inputs[0 ]->GetTransform (entity);
134+ if (rendering_mode_ == Entity::RenderingMode::kImageFilterSubpass ||
135+ rendering_mode_ == Entity::RenderingMode::kBackdropSubpass ) {
136+ Rect coverage_bounds = coverage->TransformBounds (input_transform.Invert ());
137+ Matrix transform = CalculateSubpassTransform (
138+ input_transform, effect_transform, matrix_, rendering_mode_);
139+ return coverage_bounds.TransformBounds (transform);
140+ } else {
141+ Matrix transform = input_transform * //
142+ matrix_ * //
143+ input_transform.Invert (); //
144+ return coverage->TransformBounds (transform);
145+ }
105146}
106147
107148} // namespace impeller
0 commit comments