mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] simplify render target size rounding up heuristics. (flutter/engine#57043)
Remove the over-engineered "slide around round up" herusistic for the same heuristic used by the image filters: if the coverage size is within 30% of the cull rect size, just use the cull rect size. This stabilizes allocations for the new android slide in page transition, but in a less complicated way than the old herustic.
This commit is contained in:
parent
2695e35d9d
commit
b425a87fd3
@ -12,6 +12,8 @@ bool SizeDifferenceUnderThreshold(Size a, Size b, Scalar threshold) {
|
||||
return (std::abs(a.width - b.width) / b.width) < threshold &&
|
||||
(std::abs(a.height - b.height) / b.height) < threshold;
|
||||
}
|
||||
|
||||
static constexpr Scalar kDefaultSizeThreshold = 0.3;
|
||||
} // namespace
|
||||
|
||||
std::optional<Rect> ComputeSaveLayerCoverage(
|
||||
@ -84,7 +86,8 @@ std::optional<Rect> ComputeSaveLayerCoverage(
|
||||
transformed_coverage.Intersection(source_coverage_limit.value());
|
||||
if (intersected_coverage.has_value() &&
|
||||
SizeDifferenceUnderThreshold(transformed_coverage.GetSize(),
|
||||
intersected_coverage->GetSize(), 0.2)) {
|
||||
intersected_coverage->GetSize(),
|
||||
kDefaultSizeThreshold)) {
|
||||
// Returning the transformed coverage is always correct, it just may
|
||||
// be larger than the clip area or onscreen texture.
|
||||
return transformed_coverage;
|
||||
@ -113,35 +116,16 @@ std::optional<Rect> ComputeSaveLayerCoverage(
|
||||
if (!intersection.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Sometimes a saveLayer is only slightly shifted outside of the cull rect,
|
||||
// but is being animated in. This is common for the Android slide in page
|
||||
// transitions. In these cases, computing a cull that is too tight can cause
|
||||
// thrashing of the texture cache. Instead, we try to determine the
|
||||
// intersection using only the sizing by shifting the coverage rect into the
|
||||
// cull rect origin.
|
||||
Point delta = coverage_limit.GetOrigin() - transformed_coverage.GetOrigin();
|
||||
|
||||
// This herustic is limited to perfectly vertical or horizontal transitions
|
||||
// that slide in, limited to a fixed threshold of ~30%. This value is based on
|
||||
// the Android slide in page transition which experimental has threshold
|
||||
// values of up to 28%.
|
||||
static constexpr Scalar kThresholdLimit = 0.3;
|
||||
|
||||
if (ScalarNearlyEqual(delta.y, 0) || ScalarNearlyEqual(delta.x, 0)) {
|
||||
Scalar threshold = std::max(std::abs(delta.x / coverage_limit.GetWidth()),
|
||||
std::abs(delta.y / coverage_limit.GetHeight()));
|
||||
if (threshold < kThresholdLimit) {
|
||||
std::optional<Rect> shifted_intersected_value =
|
||||
transformed_coverage.Shift(delta).Intersection(coverage_limit);
|
||||
|
||||
if (shifted_intersected_value.has_value()) {
|
||||
return shifted_intersected_value.value().Shift(-delta);
|
||||
}
|
||||
}
|
||||
// The the resulting coverage rect is nearly the same as the coverage_limit,
|
||||
// round up to the coverage_limit.
|
||||
Rect intersect_rect = intersection.value();
|
||||
if (SizeDifferenceUnderThreshold(intersect_rect.GetSize(),
|
||||
coverage_limit.GetSize(),
|
||||
kDefaultSizeThreshold)) {
|
||||
return coverage_limit;
|
||||
}
|
||||
|
||||
return intersection;
|
||||
return intersect_rect;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@ -280,77 +280,61 @@ TEST(SaveLayerUtilsTest,
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 50));
|
||||
}
|
||||
|
||||
TEST(SaveLayerUtilsTest,
|
||||
PartiallyIntersectingCoverageIgnoresOriginWithSlideSemanticsX) {
|
||||
TEST(SaveLayerUtilsTest, RoundUpCoverageWhenCloseToCoverageLimit) {
|
||||
// X varies, translation is performed on coverage.
|
||||
auto coverage = ComputeSaveLayerCoverage(
|
||||
/*content_coverage=*/Rect::MakeLTRB(5, 0, 210, 210), //
|
||||
/*effect_transform=*/{}, //
|
||||
/*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), //
|
||||
/*image_filter=*/nullptr //
|
||||
/*content_coverage=*/Rect::MakeLTRB(0, 0, 90, 90), //
|
||||
/*effect_transform=*/{}, //
|
||||
/*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), //
|
||||
/*image_filter=*/nullptr //
|
||||
);
|
||||
|
||||
ASSERT_TRUE(coverage.has_value());
|
||||
// Size that matches coverage limit
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(5, 0, 105, 100));
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 100, 100));
|
||||
}
|
||||
|
||||
TEST(SaveLayerUtilsTest, DontRoundUpCoverageWhenNotCloseToCoverageLimitWidth) {
|
||||
// X varies, translation is performed on coverage.
|
||||
auto coverage = ComputeSaveLayerCoverage(
|
||||
/*content_coverage=*/Rect::MakeLTRB(0, 0, 50, 90), //
|
||||
/*effect_transform=*/{}, //
|
||||
/*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), //
|
||||
/*image_filter=*/nullptr //
|
||||
);
|
||||
|
||||
ASSERT_TRUE(coverage.has_value());
|
||||
// Size that matches coverage limit
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 90));
|
||||
}
|
||||
|
||||
TEST(SaveLayerUtilsTest, DontRoundUpCoverageWhenNotCloseToCoverageLimitHeight) {
|
||||
// X varies, translation is performed on coverage.
|
||||
auto coverage = ComputeSaveLayerCoverage(
|
||||
/*content_coverage=*/Rect::MakeLTRB(0, 0, 90, 50), //
|
||||
/*effect_transform=*/{}, //
|
||||
/*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), //
|
||||
/*image_filter=*/nullptr //
|
||||
);
|
||||
|
||||
ASSERT_TRUE(coverage.has_value());
|
||||
// Size that matches coverage limit
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 90, 50));
|
||||
}
|
||||
|
||||
TEST(SaveLayerUtilsTest,
|
||||
PartiallyIntersectingCoverageIgnoresOriginWithSlideSemanticsY) {
|
||||
// Y varies, translation is performed on coverage.
|
||||
DontRoundUpCoverageWhenNotCloseToCoverageLimitWidthHeight) {
|
||||
// X varies, translation is performed on coverage.
|
||||
auto coverage = ComputeSaveLayerCoverage(
|
||||
/*content_coverage=*/Rect::MakeLTRB(0, 5, 210, 210), //
|
||||
/*effect_transform=*/{}, //
|
||||
/*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), //
|
||||
/*image_filter=*/nullptr //
|
||||
/*content_coverage=*/Rect::MakeLTRB(0, 0, 50, 50), //
|
||||
/*effect_transform=*/{}, //
|
||||
/*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), //
|
||||
/*image_filter=*/nullptr //
|
||||
);
|
||||
|
||||
ASSERT_TRUE(coverage.has_value());
|
||||
// Size that matches coverage limit
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 5, 100, 105));
|
||||
}
|
||||
|
||||
TEST(SaveLayerUtilsTest, PartiallyIntersectingCoverageIgnoresOriginBothXAndY) {
|
||||
// Both X and Y vary, no transation is performed.
|
||||
auto coverage = ComputeSaveLayerCoverage(
|
||||
/*content_coverage=*/Rect::MakeLTRB(5, 5, 210, 210), //
|
||||
/*effect_transform=*/{}, //
|
||||
/*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), //
|
||||
/*image_filter=*/nullptr //
|
||||
);
|
||||
|
||||
ASSERT_TRUE(coverage.has_value());
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(5, 5, 100, 100));
|
||||
}
|
||||
|
||||
TEST(SaveLayerUtilsTest, PartiallyIntersectingCoverageWithOveriszedThresholdY) {
|
||||
// Y varies, translation is not performed on coverage because it is too far
|
||||
// offscreen.
|
||||
auto coverage = ComputeSaveLayerCoverage(
|
||||
/*content_coverage=*/Rect::MakeLTRB(0, 80, 200, 200), //
|
||||
/*effect_transform=*/{}, //
|
||||
/*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), //
|
||||
/*image_filter=*/nullptr //
|
||||
);
|
||||
|
||||
ASSERT_TRUE(coverage.has_value());
|
||||
// Size that matches coverage limit
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 80, 100, 100));
|
||||
}
|
||||
|
||||
TEST(SaveLayerUtilsTest, PartiallyIntersectingCoverageWithOveriszedThresholdX) {
|
||||
// X varies, translation is not performed on coverage because it is too far
|
||||
// offscreen.
|
||||
auto coverage = ComputeSaveLayerCoverage(
|
||||
/*content_coverage=*/Rect::MakeLTRB(80, 0, 200, 200), //
|
||||
/*effect_transform=*/{}, //
|
||||
/*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), //
|
||||
/*image_filter=*/nullptr //
|
||||
);
|
||||
|
||||
ASSERT_TRUE(coverage.has_value());
|
||||
// Size that matches coverage limit
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(80, 0, 100, 100));
|
||||
EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 50));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user