Bug 164340 - REGRESSION (r206247): Painting milestones can be delayed until the next layer flush
Summary: REGRESSION (r206247): Painting milestones can be delayed until the next layer...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit2 (show other bugs)
Version: Other
Hardware: Unspecified Unspecified
: P1 Normal
Assignee: mitz
URL:
Keywords: InRadar, Regression
Depends on:
Blocks:
 
Reported: 2016-11-02 14:01 PDT by mitz
Modified: 2016-11-03 09:23 PDT (History)
7 users (show)

See Also:


Attachments
Have WebKit, not WebCore, defer sending the milestones until after the commit (7.51 KB, patch)
2016-11-02 19:09 PDT, mitz
no flags Details | Formatted Diff | Diff
Have WebKit, not WebCore, defer sending the milestones until after the commit (8.35 KB, patch)
2016-11-02 22:30 PDT, mitz
thorton: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description mitz 2016-11-02 14:01:47 PDT
After <https://trac.webkit.org/r206247> (the fix for bug 162359), it is possible for the client to not get notified of a paint milestone until the next layer flush, which may or may not occur. This is because WebCore fires painting milestones on a timer, and by the time it does so, the flush for the paint that triggered it may have already happened.
Comment 1 mitz 2016-11-02 14:06:18 PDT
<rdar://problem/29074344>
Comment 2 mitz 2016-11-02 14:20:10 PDT
Perhaps the timer is not the reason. TiledCoreAnimationDrawingArea::flushLayers is called long before RenderLayerCompositor::didPaintBacking.
Comment 3 Simon Fraser (smfr) 2016-11-02 14:34:31 PDT
If some data in the commit will change, we should schedule a commit.
Comment 4 mitz 2016-11-02 14:55:00 PDT
(In reply to comment #2)
> Perhaps the timer is not the reason.
> TiledCoreAnimationDrawingArea::flushLayers is called long before
> RenderLayerCompositor::didPaintBacking.

TiledCoreAnimationDrawingArea::flushLayers installs a commit handler, and that runs after didPaintBacking. So we need to fire the pending milestones from there.
Comment 5 mitz 2016-11-02 17:41:49 PDT
Actually, I am seeing this with the root layer, which doesn’t even rely on RenderLayerCompositor::didPaintBacking, because RenderLayerBacking::paintIntoLayer calls FrameView::didPaintContents() directly which calls firePaintRelatedMilestonesIfNeeded() without a timer delay.

I am trying to understand in what cases that is not followed by a flush, so that I cam make a reliable test case for the fix that moves firing the pending milestones into the commit handler.

I am also trying to understand what’s the right thing to do for OS X 10.10, which doesn’t use the commit handler code path.
Comment 6 mitz 2016-11-02 19:09:27 PDT
Created attachment 293734 [details]
Have WebKit, not WebCore, defer sending the milestones until after the commit

I wasn’t able to add an API test for this. I test with internal builds of macOS Mail, which were affected by the bug.
Comment 7 Simon Fraser (smfr) 2016-11-02 19:18:28 PDT
Comment on attachment 293734 [details]
Have WebKit, not WebCore, defer sending the milestones until after the commit

View in context: https://bugs.webkit.org/attachment.cgi?id=293734&action=review

> Source/WebCore/ChangeLog:11
> +        To give WebKit a chance to deliver the painting milestones to its client after the commit,
> +        we must tell it about them before or during the commit. To that end, we should not defer
> +        the call to firePaintRelatedMilestonesIfNeeded until after the commit.

Was it deferred for a good reason, like coalescing?

> Source/WebCore/rendering/RenderLayerCompositor.cpp:572
> +        frameView.firePaintRelatedMilestonesIfNeeded();

Does one really "fire" a milestone, or just reach or pass it?

> Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:428
> +            if (TiledCoreAnimationDrawingArea* drawingArea = static_cast<TiledCoreAnimationDrawingArea*>(retainedPage->drawingArea())) {

auto foo = downcast<TiledCoreAnimationDrawingArea>() ?

When is drawingArea != this? Very confusing to fetch it here again.

> Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:431
> +                if (drawingArea->m_pendingNewlyReachedLayoutMilestones)
> +                    retainedPage->send(Messages::WebPageProxy::DidReachLayoutMilestone(drawingArea->m_pendingNewlyReachedLayoutMilestones));
> +                drawingArea->m_pendingNewlyReachedLayoutMilestones = 0;

I would like to see this moved to a self-contained function.

> Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:439
> +                if (drawingArea->m_pendingNewlyReachedLayoutMilestones)
> +                    retainedPage->send(Messages::WebPageProxy::DidReachLayoutMilestone(drawingArea->m_pendingNewlyReachedLayoutMilestones));
> +                drawingArea->m_pendingNewlyReachedLayoutMilestones = 0;

...which you could also call here.
Comment 8 mitz 2016-11-02 21:06:42 PDT
Comment on attachment 293734 [details]
Have WebKit, not WebCore, defer sending the milestones until after the commit

View in context: https://bugs.webkit.org/attachment.cgi?id=293734&action=review

>> Source/WebCore/ChangeLog:11
>> +        the call to firePaintRelatedMilestonesIfNeeded until after the commit.
> 
> Was it deferred for a good reason, like coalescing?

It was deferred in order to make sure that WebKit client gets notified only after the commit (see bug 115753). That bug was probably reintroduced when <https://trac.webkit.org/r166015> (the fix for bug 130541) made RenderLayerBacking::paintIntoLayer() call FrameView::didPaintContents(), which fires the paint-related milestones synchronously. That is, until <https://trac.webkit.org/r206247> introduced a completely different way for the milestones to be deferred, which happened to defer them too much in some cases.

>> Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:428
>> +            if (TiledCoreAnimationDrawingArea* drawingArea = static_cast<TiledCoreAnimationDrawingArea*>(retainedPage->drawingArea())) {
> 
> auto foo = downcast<TiledCoreAnimationDrawingArea>() ?
> 
> When is drawingArea != this? Very confusing to fetch it here again.

drawingArea is null if in the mean while WebPage::close has been called.

>> Source/WebKit2/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm:439
>> +                drawingArea->m_pendingNewlyReachedLayoutMilestones = 0;
> 
> ...which you could also call here.

I waffled on this. It will be a similar number of lines of code, and once 10.10 support is gone, it will be even more silly for it to be a function.
Comment 9 mitz 2016-11-02 22:30:56 PDT
Created attachment 293747 [details]
Have WebKit, not WebCore, defer sending the milestones until after the commit

Made a helper function
Comment 10 mitz 2016-11-03 09:23:02 PDT
Fixed in <https://trac.webkit.org/r208328>.