diff --git a/impeller/entity/save_layer_utils.cc b/impeller/entity/save_layer_utils.cc index 8d10181198b1d..f6ad180f8cfba 100644 --- a/impeller/entity/save_layer_utils.cc +++ b/impeller/entity/save_layer_utils.cc @@ -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 ComputeSaveLayerCoverage( @@ -84,7 +86,8 @@ std::optional 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 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 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 diff --git a/impeller/entity/save_layer_utils_unittests.cc b/impeller/entity/save_layer_utils_unittests.cc index d86c8209ab6e3..5139204d7c2af 100644 --- a/impeller/entity/save_layer_utils_unittests.cc +++ b/impeller/entity/save_layer_utils_unittests.cc @@ -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, - PartiallyIntersectingCoverageIgnoresOriginWithSlideSemanticsY) { - // Y varies, translation is performed on coverage. +TEST(SaveLayerUtilsTest, DontRoundUpCoverageWhenNotCloseToCoverageLimitWidth) { + // 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, 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, 5, 100, 105)); + EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 90)); } -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. +TEST(SaveLayerUtilsTest, DontRoundUpCoverageWhenNotCloseToCoverageLimitHeight) { + // X varies, translation is performed on coverage. auto coverage = ComputeSaveLayerCoverage( - /*content_coverage=*/Rect::MakeLTRB(0, 80, 200, 200), // - /*effect_transform=*/{}, // - /*coverage_limit=*/Rect::MakeLTRB(0, 0, 100, 100), // - /*image_filter=*/nullptr // + /*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, 80, 100, 100)); + EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 90, 50)); } -TEST(SaveLayerUtilsTest, PartiallyIntersectingCoverageWithOveriszedThresholdX) { - // X varies, translation is not performed on coverage because it is too far - // offscreen. +TEST(SaveLayerUtilsTest, + DontRoundUpCoverageWhenNotCloseToCoverageLimitWidthHeight) { + // X varies, translation is performed on coverage. auto coverage = ComputeSaveLayerCoverage( - /*content_coverage=*/Rect::MakeLTRB(80, 0, 200, 200), // - /*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(80, 0, 100, 100)); + EXPECT_EQ(coverage.value(), Rect::MakeLTRB(0, 0, 50, 50)); } } // namespace testing