Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[Impeller] Fix MatrixFilter multiplication ordering for subpasses. (#…
…43943)

Resolves flutter/flutter#130355.

When drawing a backdrop filter, we offset the backdrop entity with
`-local_pass_position` in order to align the backdrop texture with the
position of the pass it's being drawn to. When rendering the filter,
this transform propagates to the filter snapshot. Prior to this change,
that offset was being applied within the space of the backdrop filter's
matrix, which is wrong! It needs to be applied in screen space.

We didn't notice this prior to the coverage hint optimization because we
were previously forcing subpass sizes to match the parent whenever a
backdrop filter was present.

This one was very difficult to reason through at first, and so I added a
detailed comment to explain the rationale behind the behavioral
differences between the backdrop filter and non-backdrop filter cases of
the matrix filter.
  • Loading branch information
bdero authored and gaaclarke committed May 16, 2024
commit 464a8c6c1143e8ff4c22ce22845fc58d6d3627e4
62 changes: 39 additions & 23 deletions impeller/entity/contents/filters/matrix_filter_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,45 @@ std::optional<Entity> MatrixFilterContents::RenderFilter(
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;

if (rendering_mode_ == Entity::RenderingMode::kSubpass) {
// There are two special quirks with how Matrix filters behave when used as
// subpass backdrop filters:
//
// 1. For subpass backdrop filters, the snapshot transform is always just a
// translation that positions the parent pass texture correctly relative
// to the subpass texture. However, this translation always needs to be
// applied in screen space.
//
// Since we know the snapshot transform will always have an identity
// basis in this case, we safely reverse the order and apply the filter's
// matrix within the snapshot transform space.
//
// 2. The filter's matrix needs to be applied within the space defined by
// the scene's current transformation matrix (CTM). For example: If the
// CTM is scaled up, then translations applied by the matrix should be
// magnified accordingly.
//
// To accomplish this, we sandwitch 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.
//

snapshot->transform = snapshot->transform * //
effect_transform * //
matrix_ * //
effect_transform.Invert();
} else {
snapshot->transform = entity.GetTransform() * //
matrix_ * //
entity.GetTransform().Invert() * //
snapshot->transform;
}
snapshot->sampler_descriptor = sampler_descriptor_;
if (!snapshot.has_value()) {
return std::nullopt;
Expand Down