Commit bb0f9dfb authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Commit Bot

Fix false-positive of under-invalidation checking

If a subsequence was fully painted the last time, we don't repaint the
subsequence on interest rect change because the fully painted result is
still useable. However this triggers false-positive of under-
invalidation checking which strictly matches new and cached
subsequences.

Bug: 755478
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: I24f8fa9c2e3167ff3c54954bf5e994a74ef70056
Reviewed-on: https://chromium-review.googlesource.com/661379
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: default avatarChris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#501161}
parent 038025ec
...@@ -385,7 +385,7 @@ Bug(none) compositing/squashing/repaint-child-of-squashed.html [ Failure ] ...@@ -385,7 +385,7 @@ Bug(none) compositing/squashing/repaint-child-of-squashed.html [ Failure ]
Bug(none) compositing/squashing/selection-repaint-with-gaps.html [ Failure ] Bug(none) compositing/squashing/selection-repaint-with-gaps.html [ Failure ]
Bug(none) compositing/squashing/squash-above-fixed-1.html [ Failure ] Bug(none) compositing/squashing/squash-above-fixed-1.html [ Failure ]
Bug(none) compositing/squashing/squash-above-fixed-2.html [ Crash Failure ] Bug(none) compositing/squashing/squash-above-fixed-2.html [ Crash Failure ]
Bug(none) compositing/squashing/squash-above-fixed-3.html [ Failure ] Bug(none) compositing/squashing/squash-above-fixed-3.html [ Crash Failure ]
Bug(none) compositing/squashing/squash-compositing-hover.html [ Failure ] Bug(none) compositing/squashing/squash-compositing-hover.html [ Failure ]
Bug(none) compositing/squashing/squash-onto-distant-relative.html [ Failure ] Bug(none) compositing/squashing/squash-onto-distant-relative.html [ Failure ]
Bug(none) compositing/squashing/squash-onto-nephew.html [ Failure ] Bug(none) compositing/squashing/squash-onto-nephew.html [ Failure ]
......
...@@ -230,7 +230,12 @@ static bool ShouldRepaintSubsequence( ...@@ -230,7 +230,12 @@ static bool ShouldRepaintSubsequence(
// Repaint if previously the layer might be clipped by paintDirtyRect and // Repaint if previously the layer might be clipped by paintDirtyRect and
// paintDirtyRect changes. // paintDirtyRect changes.
if (paint_layer.PreviousPaintResult() == kMayBeClippedByPaintDirtyRect && if ((paint_layer.PreviousPaintResult() == kMayBeClippedByPaintDirtyRect ||
// When PaintUnderInvalidationChecking is enabled, always repaint the
// subsequence when the paint rect changes because we will strictly match
// new and cached subsequences. Normally we can reuse the cached fully
// painted subsequence even if we would partially paint this time.
RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) &&
paint_layer.PreviousPaintDirtyRect() != painting_info.paint_dirty_rect) { paint_layer.PreviousPaintDirtyRect() != painting_info.paint_dirty_rect) {
needs_repaint = true; needs_repaint = true;
should_clear_empty_paint_phase_flags = true; should_clear_empty_paint_phase_flags = true;
......
...@@ -271,6 +271,29 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceOnInterestRectChange) { ...@@ -271,6 +271,29 @@ TEST_P(PaintLayerPainterTest, CachedSubsequenceOnInterestRectChange) {
TestDisplayItem(content2b, kBackgroundType)); TestDisplayItem(content2b, kBackgroundType));
} }
TEST_P(PaintLayerPainterTest,
CachedSubsequenceOnInterestRectChangeUnderInvalidationChecking) {
ScopedPaintUnderInvalidationCheckingForTest under_invalidation_checking(true);
SetBodyInnerHTML(
"<style>p { width: 200px; height: 50px; background: green }</style>"
"<div id='target' style='position: relative; z-index: 1'>"
" <p></p><p></p><p></p><p></p>"
"</div>");
RootPaintController().InvalidateAll();
// |target| will be fully painted.
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
IntRect interest_rect(0, 0, 400, 300);
Paint(&interest_rect);
// |target| will be partially painted. Should not trigger under-invalidation
// checking DCHECKs.
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
IntRect new_interest_rect(0, 100, 300, 1000);
Paint(&new_interest_rect);
}
TEST_P(PaintLayerPainterTest, TEST_P(PaintLayerPainterTest,
CachedSubsequenceOnStyleChangeWithInterestRectClipping) { CachedSubsequenceOnStyleChangeWithInterestRectClipping) {
SetBodyInnerHTML( SetBodyInnerHTML(
......
...@@ -173,18 +173,9 @@ size_t PaintController::BeginSubsequence() { ...@@ -173,18 +173,9 @@ size_t PaintController::BeginSubsequence() {
void PaintController::EndSubsequence(const DisplayItemClient& client, void PaintController::EndSubsequence(const DisplayItemClient& client,
size_t start) { size_t start) {
size_t end = new_display_item_list_.size(); size_t end = new_display_item_list_.size();
if (start == end) {
// Omit the empty subsequence. The forcing-new-chunk flag set by
// BeginSubsequence() still applies, but this not a big deal because empty
// subsequences are not common. Also we should not clear the flag because
// there might be unhandled flag that was set before this empty subsequence.
return;
}
// Force new paint chunk which is required for subsequence caching.
new_paint_chunks_.ForceNewChunk();
if (IsCheckingUnderInvalidation()) { if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() &&
IsCheckingUnderInvalidation()) {
SubsequenceMarkers* markers = GetSubsequenceMarkers(client); SubsequenceMarkers* markers = GetSubsequenceMarkers(client);
if (!markers) { if (!markers) {
ShowSequenceUnderInvalidationError( ShowSequenceUnderInvalidationError(
...@@ -197,8 +188,20 @@ void PaintController::EndSubsequence(const DisplayItemClient& client, ...@@ -197,8 +188,20 @@ void PaintController::EndSubsequence(const DisplayItemClient& client,
end); end);
CHECK(false); CHECK(false);
} }
under_invalidation_checking_end_ = 0;
} }
if (start == end) {
// Omit the empty subsequence. The forcing-new-chunk flag set by
// BeginSubsequence() still applies, but this not a big deal because empty
// subsequences are not common. Also we should not clear the flag because
// there might be unhandled flag that was set before this empty subsequence.
return;
}
// Force new paint chunk which is required for subsequence caching.
new_paint_chunks_.ForceNewChunk();
DCHECK(new_cached_subsequences_.find(&client) == DCHECK(new_cached_subsequences_.find(&client) ==
new_cached_subsequences_.end()); new_cached_subsequences_.end());
......
...@@ -306,9 +306,8 @@ class PLATFORM_EXPORT PaintController { ...@@ -306,9 +306,8 @@ class PLATFORM_EXPORT PaintController {
void CheckUnderInvalidation(); void CheckUnderInvalidation();
bool IsCheckingUnderInvalidation() const { bool IsCheckingUnderInvalidation() const {
return under_invalidation_checking_end_ - return under_invalidation_checking_end_ >
under_invalidation_checking_begin_ > under_invalidation_checking_begin_;
0;
} }
struct SubsequenceMarkers { struct SubsequenceMarkers {
......
...@@ -2387,6 +2387,25 @@ class PaintControllerUnderInvalidationTest ...@@ -2387,6 +2387,25 @@ class PaintControllerUnderInvalidationTest
} }
GetPaintController().CommitNewDisplayItems(); GetPaintController().CommitNewDisplayItems();
} }
void TestSubsequenceBecomesEmpty() {
FakeDisplayItemClient target("target");
GraphicsContext context(GetPaintController());
{
SubsequenceRecorder r(context, target);
DrawRect(context, target, kBackgroundDrawingType,
FloatRect(100, 100, 300, 300));
}
GetPaintController().CommitNewDisplayItems();
{
EXPECT_FALSE(
SubsequenceRecorder::UseCachedSubsequenceIfPossible(context, target));
SubsequenceRecorder r(context, target);
}
GetPaintController().CommitNewDisplayItems();
}
}; };
TEST_F(PaintControllerUnderInvalidationTest, ChangeDrawing) { TEST_F(PaintControllerUnderInvalidationTest, ChangeDrawing) {
...@@ -2436,6 +2455,10 @@ TEST_F(PaintControllerUnderInvalidationTest, InvalidationInSubsequence) { ...@@ -2436,6 +2455,10 @@ TEST_F(PaintControllerUnderInvalidationTest, InvalidationInSubsequence) {
TestInvalidationInSubsequence(); TestInvalidationInSubsequence();
} }
TEST_F(PaintControllerUnderInvalidationTest, SubsequenceBecomesEmpty) {
EXPECT_DEATH(TestSubsequenceBecomesEmpty(), "");
}
#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
} // namespace blink } // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment