blob: 7ec6c047b0f2ce07090dc239930696c150483f83 [file] [log] [blame] [edit]
// 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 "flutter/testing/testing.h"
#include "gtest/gtest.h"
#include "impeller/entity/contents/clip_contents.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/entity_pass_clip_stack.h"
namespace impeller {
namespace testing {
TEST(EntityPassClipStackTest, CanPushAndPopEntities) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
EXPECT_TRUE(recorder.GetReplayEntities().empty());
recorder.RecordClip(ClipContents(Rect::MakeLTRB(0, 0, 100, 100),
/*is_axis_aligned_rect=*/false),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
recorder.RecordClip(ClipContents(Rect::MakeLTRB(0, 0, 50.5, 50.5),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 2, 100, /*is_aa=*/true);
EXPECT_EQ(recorder.GetReplayEntities().size(), 2u);
ASSERT_TRUE(recorder.GetReplayEntities()[0].clip_coverage.has_value());
ASSERT_TRUE(recorder.GetReplayEntities()[1].clip_coverage.has_value());
// NOLINTBEGIN(bugprone-unchecked-optional-access)
EXPECT_EQ(recorder.GetReplayEntities()[0].clip_coverage.value(),
Rect::MakeLTRB(0, 0, 100, 100));
EXPECT_EQ(recorder.GetReplayEntities()[1].clip_coverage.value(),
Rect::MakeLTRB(0, 0, 50.5, 50.5));
// NOLINTEND(bugprone-unchecked-optional-access)
recorder.RecordRestore({0, 0}, 1);
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
recorder.RecordRestore({0, 0}, 0);
EXPECT_TRUE(recorder.GetReplayEntities().empty());
}
TEST(EntityPassClipStackTest, CanPopEntitiesSafely) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
EXPECT_TRUE(recorder.GetReplayEntities().empty());
recorder.RecordRestore({0, 0}, 0);
EXPECT_TRUE(recorder.GetReplayEntities().empty());
}
TEST(EntityPassClipStackTest, AppendAndRestoreClipCoverage) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push a clip.
EntityPassClipStack::ClipStateResult result =
recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.5, 55.5),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
EXPECT_TRUE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(50, 50, 55.5, 55.5));
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
// Restore the clip.
recorder.RecordRestore({0, 0}, 0);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeSize(Size::MakeWH(100, 100)));
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
}
TEST(EntityPassClipStackTest, AppendAndRestoreClipCoverageNonAA) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push a clip.
EntityPassClipStack::ClipStateResult result =
recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.4, 55.4),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/false);
EXPECT_FALSE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(50, 50, 55, 55));
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
// Restore the clip.
recorder.RecordRestore({0, 0}, 0);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeSize(Size::MakeWH(100, 100)));
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
}
// Append two clip coverages, the second is larger the first. This
// should result in the second clip not requiring any update.
TEST(EntityPassClipStackTest, AppendLargerClipCoverage) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push a clip.
EntityPassClipStack::ClipStateResult result =
recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.5, 55.5),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
EXPECT_TRUE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
// Push a clip with larger coverage than the previous state.
result = recorder.RecordClip(ClipContents(Rect::MakeLTRB(0, 0, 100.5, 100.5),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 1, 100, /*is_aa=*/true);
EXPECT_FALSE(result.should_render);
EXPECT_FALSE(result.clip_did_change);
}
// Since clip entities return the outer coverage we can only cull axis aligned
// rectangles and intersect clips.
TEST(EntityPassClipStackTest,
AppendLargerClipCoverageWithDifferenceOrNonSquare) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push a clip.
EntityPassClipStack::ClipStateResult result =
recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55, 55),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
EXPECT_FALSE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
// Push a clip with larger coverage than the previous state.
result = recorder.RecordClip(ClipContents(Rect::MakeLTRB(0, 0, 100, 100),
/*is_axis_aligned_rect=*/false),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
EXPECT_TRUE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
}
TEST(EntityPassClipStackTest, AppendDecreasingSizeClipCoverage) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push Clips that shrink in size. All should be applied.
Entity entity;
for (auto i = 1; i < 20; i++) {
EntityPassClipStack::ClipStateResult result = recorder.RecordClip(
ClipContents(Rect::MakeLTRB(i, i, 99.6 - i, 99.6 - i),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
EXPECT_TRUE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
EXPECT_EQ(recorder.CurrentClipCoverage(),
Rect::MakeLTRB(i, i, 99.6 - i, 99.6 - i));
}
}
TEST(EntityPassClipStackTest, AppendIncreasingSizeClipCoverage) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push Clips that grow in size. All should be skipped.
for (auto i = 1; i < 20; i++) {
EntityPassClipStack::ClipStateResult result = recorder.RecordClip(
ClipContents(Rect::MakeLTRB(0 - i, 0 - i, 100 + i, 100 + i),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
EXPECT_FALSE(result.should_render);
EXPECT_FALSE(result.clip_did_change);
EXPECT_EQ(recorder.CurrentClipCoverage(), Rect::MakeLTRB(0, 0, 100, 100));
}
}
TEST(EntityPassClipStackTest, UnbalancedRestore) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Restore the clip.
EntityPassClipStack::ClipStateResult result =
recorder.RecordRestore(Point(0, 0), 0);
EXPECT_FALSE(result.should_render);
EXPECT_FALSE(result.clip_did_change);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeSize(Size::MakeWH(100, 100)));
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
}
TEST(EntityPassClipStackTest, ClipAndRestoreWithSubpasses) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push a clip.
{
EntityPassClipStack::ClipStateResult result =
recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.5, 55.5),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
EXPECT_TRUE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
}
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(50, 50, 55.5, 55.5));
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
// Begin a subpass.
recorder.PushSubpass(Rect::MakeLTRB(50, 50, 55, 55), 1);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeLTRB(50, 50, 55, 55));
{
EntityPassClipStack::ClipStateResult result =
recorder.RecordClip(ClipContents(Rect::MakeLTRB(54, 54, 54.5, 54.5),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
EXPECT_TRUE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
}
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(54, 54, 54.5, 54.5));
// End subpass.
recorder.PopSubpass();
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(50, 50, 55.5, 55.5));
}
TEST(EntityPassClipStackTest, ClipAndRestoreWithSubpassesNonAA) {
EntityPassClipStack recorder =
EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
// Push a clip.
{
EntityPassClipStack::ClipStateResult result =
recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.4, 55.4),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/false);
EXPECT_FALSE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
}
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(50, 50, 55.0, 55.0));
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
// Begin a subpass.
recorder.PushSubpass(Rect::MakeLTRB(50, 50, 55, 55), 1);
ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
Rect::MakeLTRB(50, 50, 55, 55));
{
EntityPassClipStack::ClipStateResult result =
recorder.RecordClip(ClipContents(Rect::MakeLTRB(54, 54, 55.4, 55.4),
/*is_axis_aligned_rect=*/true),
Matrix(), {0, 0}, 0, 100, /*is_aa=*/false);
EXPECT_FALSE(result.should_render);
EXPECT_TRUE(result.clip_did_change);
}
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(54, 54, 55.0, 55.0));
// End subpass.
recorder.PopSubpass();
EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
Rect::MakeLTRB(50, 50, 55, 55));
}
} // namespace testing
} // namespace impeller