Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 8640101

Browse files
authored
[CP][Impeller] Use basis of effect transform in MatrixFilter. (#44015)
Cherry-pick of #43990.
1 parent c1f977f commit 8640101

File tree

3 files changed

+97
-19
lines changed

3 files changed

+97
-19
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2854,5 +2854,65 @@ TEST_P(AiksTest, TextForegroundShaderWithTransform) {
28542854
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
28552855
}
28562856

2857+
TEST_P(AiksTest, MatrixSaveLayerFilter) {
2858+
Canvas canvas;
2859+
canvas.DrawPaint({.color = Color::Black()});
2860+
canvas.SaveLayer({}, std::nullopt);
2861+
{
2862+
canvas.DrawCircle(Point(200, 200), 100,
2863+
{.color = Color::Green().WithAlpha(0.5),
2864+
.blend_mode = BlendMode::kPlus});
2865+
// Should render a second circle, centered on the bottom-right-most edge of
2866+
// the circle.
2867+
canvas.SaveLayer({.image_filter =
2868+
[](const FilterInput::Ref& input,
2869+
const Matrix& effect_transform, bool is_subpass) {
2870+
Matrix matrix =
2871+
Matrix::MakeTranslation(
2872+
Vector2(1, 1) * (100 + 100 * k1OverSqrt2)) *
2873+
Matrix::MakeScale(Vector2(1, 1) * 0.2) *
2874+
Matrix::MakeTranslation(Vector2(-100, -100));
2875+
return FilterContents::MakeMatrixFilter(
2876+
input, matrix, {}, Matrix(), true);
2877+
}},
2878+
std::nullopt);
2879+
canvas.DrawCircle(Point(200, 200), 100,
2880+
{.color = Color::Green().WithAlpha(0.5),
2881+
.blend_mode = BlendMode::kPlus});
2882+
canvas.Restore();
2883+
}
2884+
canvas.Restore();
2885+
2886+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
2887+
}
2888+
2889+
TEST_P(AiksTest, MatrixBackdropFilter) {
2890+
Canvas canvas;
2891+
canvas.DrawPaint({.color = Color::Black()});
2892+
canvas.SaveLayer({}, std::nullopt);
2893+
{
2894+
canvas.DrawCircle(Point(200, 200), 100,
2895+
{.color = Color::Green().WithAlpha(0.5),
2896+
.blend_mode = BlendMode::kPlus});
2897+
// Should render a second circle, centered on the bottom-right-most edge of
2898+
// the circle.
2899+
canvas.SaveLayer({}, std::nullopt,
2900+
[](const FilterInput::Ref& input,
2901+
const Matrix& effect_transform, bool is_subpass) {
2902+
Matrix matrix =
2903+
Matrix::MakeTranslation(Vector2(1, 1) *
2904+
(100 + 100 * k1OverSqrt2)) *
2905+
Matrix::MakeScale(Vector2(1, 1) * 0.2) *
2906+
Matrix::MakeTranslation(Vector2(-100, -100));
2907+
return FilterContents::MakeMatrixFilter(
2908+
input, matrix, {}, Matrix(), true);
2909+
});
2910+
canvas.Restore();
2911+
}
2912+
canvas.Restore();
2913+
2914+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
2915+
}
2916+
28572917
} // namespace testing
28582918
} // namespace impeller

impeller/entity/contents/filters/matrix_filter_contents.cc

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,27 @@ std::optional<Entity> MatrixFilterContents::RenderFilter(
3434
return std::nullopt;
3535
}
3636

37-
auto& transform = is_subpass_ ? effect_transform : entity.GetTransformation();
37+
// The filter's matrix needs to be applied within the space defined by the
38+
// scene's current transformation matrix (CTM). For example: If the CTM is
39+
// scaled up, then translations applied by the matrix should be magnified
40+
// accordingly.
41+
//
42+
// To accomplish this, we sandwitch the filter's matrix within the CTM in both
43+
// cases. But notice that for the subpass backdrop filter case, we use the
44+
// "effect transform" instead of the Entity's transform!
45+
//
46+
// That's because in the subpass backdrop filter case, the Entity's transform
47+
// isn't actually the captured CTM of the scene like it usually is; instead,
48+
// it's just a screen space translation that offsets the backdrop texture (as
49+
// mentioned above). And so we sneak the subpass's captured CTM in through the
50+
// effect transform.
51+
52+
auto transform = is_subpass_ ? effect_transform : entity.GetTransformation();
3853
snapshot->transform = transform * //
3954
matrix_ * //
4055
transform.Invert() * //
4156
snapshot->transform;
57+
4258
snapshot->sampler_descriptor = sampler_descriptor_;
4359
return Entity::FromSnapshot(snapshot, entity.GetBlendMode(),
4460
entity.GetStencilDepth());

impeller/entity/entity_pass.cc

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -434,14 +434,14 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
434434
return EntityPass::EntityResult::Skip();
435435
}
436436

437-
std::shared_ptr<Contents> backdrop_filter_contents = nullptr;
437+
std::shared_ptr<Contents> subpass_backdrop_filter_contents = nullptr;
438438
if (subpass->backdrop_filter_proc_) {
439439
auto texture = pass_context.GetTexture();
440440
// Render the backdrop texture before any of the pass elements.
441441
const auto& proc = subpass->backdrop_filter_proc_;
442-
backdrop_filter_contents =
443-
proc(FilterInput::Make(std::move(texture)), subpass->xformation_,
444-
/*is_subpass*/ true);
442+
subpass_backdrop_filter_contents = proc(
443+
FilterInput::Make(std::move(texture)), subpass->xformation_.Basis(),
444+
/*is_subpass*/ true);
445445

446446
// The subpass will need to read from the current pass texture when
447447
// rendering the backdrop, so if there's an active pass, end it prior to
@@ -476,9 +476,10 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
476476
return EntityPass::EntityResult::Skip();
477477
}
478478

479-
auto subpass_coverage = (subpass->flood_clip_ || backdrop_filter_contents)
480-
? coverage_limit
481-
: GetSubpassCoverage(*subpass, coverage_limit);
479+
auto subpass_coverage =
480+
(subpass->flood_clip_ || subpass_backdrop_filter_contents)
481+
? coverage_limit
482+
: GetSubpassCoverage(*subpass, coverage_limit);
482483
if (!subpass_coverage.has_value()) {
483484
return EntityPass::EntityResult::Skip();
484485
}
@@ -501,17 +502,18 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
501502

502503
// Stencil textures aren't shared between EntityPasses (as much of the
503504
// time they are transient).
504-
if (!subpass->OnRender(renderer, // renderer
505-
root_pass_size, // root_pass_size
506-
subpass_target, // pass_target
507-
subpass_coverage->origin, // global_pass_position
508-
subpass_coverage->origin -
509-
global_pass_position, // local_pass_position
510-
++pass_depth, // pass_depth
511-
stencil_coverage_stack, // stencil_coverage_stack
512-
subpass->stencil_depth_, // stencil_depth_floor
513-
backdrop_filter_contents // backdrop_filter_contents
514-
)) {
505+
if (!subpass->OnRender(
506+
renderer, // renderer
507+
root_pass_size, // root_pass_size
508+
subpass_target, // pass_target
509+
subpass_coverage->origin, // global_pass_position
510+
subpass_coverage->origin -
511+
global_pass_position, // local_pass_position
512+
++pass_depth, // pass_depth
513+
stencil_coverage_stack, // stencil_coverage_stack
514+
subpass->stencil_depth_, // stencil_depth_floor
515+
subpass_backdrop_filter_contents // backdrop_filter_contents
516+
)) {
515517
// Validation error messages are triggered for all `OnRender()` failure
516518
// cases.
517519
return EntityPass::EntityResult::Failure();

0 commit comments

Comments
 (0)