⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 261985 in webkit


Ignore:
Timestamp:
May 20, 2020, 11:47:24 PM (6 years ago)
Author:
Simon Fraser
Message:

[macOS] Scrolling synchronization part 1: Have the scrolling thread wait half a frame for the main thread to complete the rendering update
https://bugs.webkit.org/show_bug.cgi?id=212168

Reviewed by Tim Horton.

Source/WebCore:

Currently the scrolling thread is a free-running thread that moves layers around in response
to wheel events, and asynchronously posts data about scrolled layers back to the main thread.
That results in an almost guaranteed lack of synchronization between the displayed layer
positions, and the web-exposed values for scroll position (element.scrollTop, window.pageYOffset etc).
This is a frequent source of stuttering or jumpy web content when scrolling.

The first step to fixing this is to synchronize the scrolling thread layer positions
and the main thread state for the case where the main thread is responsive enough to
render once per frame. This is achieved as follow:

  • When the main thread is starting a rendering update, Page::updateRendering() informs the scrolling tree via ScrollingCoordinatorMac::willStartRenderingUpdate(). This atomically waits for the scrolling thread to take the m_treeMutex (via a BinarySemaphore) and starts waiting on the m_stateCondition Condition. Now the main thread pulls the state of the scrolling tree via synchronizeStateFromScrollingTree() and uses it for the rendering update.
  • If the rendering update finishes within half a frame (8ms), then m_stateCondition is released, and the scrolling thread assumes that the main thread is going to commit layers rapidly enough to preserve 60fps scrolling.
  • If the rendering update takes too long, m_stateCondition times out, and the scrolling thread applies layer positions, triggering a CA commit on that thread.

We no longer apply layer positions directly when handling wheel events.

synchronizeStateFromScrollingTree() has to only pull state from nodes that have moved on the scrolling thread,
so track that via ScrollingTreeScrollingNode::scrolledSinceLastCommit() and adjust the visitor function to
make it available during scrolling tree traversal.

  • page/Page.cpp:

(WebCore::Page::updateRendering):
(WebCore::Page::finalizeRenderingUpdate):

  • page/scrolling/AsyncScrollingCoordinator.cpp:

(WebCore::AsyncScrollingCoordinator::synchronizeStateFromScrollingTree):

  • page/scrolling/AsyncScrollingCoordinator.h:
  • page/scrolling/ScrollingCoordinator.h:

(WebCore::ScrollingCoordinator::willStartRenderingUpdate):
(WebCore::ScrollingCoordinator::didCompleteRenderingUpdate):
(WebCore::ScrollingCoordinator::synchronizeStateFromScrollingTree): Deleted.

  • page/scrolling/ScrollingTree.cpp:

(WebCore::ScrollingTree::handleWheelEvent):
(WebCore::ScrollingTree::traverseScrollingTreeRecursive):
(WebCore::ScrollingTree::commitTreeState):
(WebCore::ScrollingTree::updateTreeFromStateNodeRecursive):
(WebCore::ScrollingTree::applyLayerPositionsInternal):
(WebCore::ScrollingTree::nominalFramesPerSecond):

  • page/scrolling/ScrollingTree.h:
  • page/scrolling/ScrollingTreeNode.h:

(WebCore::ScrollingTreeNode::didCompleteCommitForNode):

  • page/scrolling/ScrollingTreeScrollingNode.cpp:

(WebCore::ScrollingTreeScrollingNode::didCompleteCommitForNode):
(WebCore::ScrollingTreeScrollingNode::currentScrollPositionChanged):

  • page/scrolling/ScrollingTreeScrollingNode.h:
  • page/scrolling/ThreadedScrollingTree.cpp:

(WebCore::ThreadedScrollingTree::willStartRenderingUpdate):
(WebCore::ThreadedScrollingTree::maxAllowableRenderingUpdateDurationForSynchronization):
(WebCore::ThreadedScrollingTree::waitForRenderingUpdateCompletionOrTimeout):
(WebCore::ThreadedScrollingTree::didCompleteRenderingUpdate):
(WebCore::ThreadedScrollingTree::displayDidRefreshOnScrollingThread):

  • page/scrolling/ThreadedScrollingTree.h:

(WebCore::ThreadedScrollingTree::treeMutex):

  • page/scrolling/mac/ScrollingCoordinatorMac.h:
  • page/scrolling/mac/ScrollingCoordinatorMac.mm:

(WebCore::ScrollingCoordinatorMac::willStartRenderingUpdate):
(WebCore::ScrollingCoordinatorMac::didCompleteRenderingUpdate):

Source/WTF:

Some new trace points for scrolling thread activity.

  • wtf/SystemTracing.h:

Tools:

Some new trace points for scrolling thread activity.

  • Tracing/SystemTracePoints.plist:
Location:
trunk
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r261978 r261985  
     12020-05-20  Simon Fraser  <simon.fraser@apple.com>
     2
     3        [macOS] Scrolling synchronization part 1: Have the scrolling thread wait half a frame for the main thread to complete the rendering update
     4        https://bugs.webkit.org/show_bug.cgi?id=212168
     5
     6        Reviewed by Tim Horton.
     7
     8        Some new trace points for scrolling thread activity.
     9
     10        * wtf/SystemTracing.h:
     11
    1122020-05-20  Tim Horton  <timothy_horton@apple.com>
    213
  • trunk/Source/WTF/wtf/SystemTracing.h

    r257898 r261985  
    9191    DisplayListReplayStart,
    9292    DisplayListReplayEnd,
     93    ScrollingThreadRenderUpdateSyncStart,
     94    ScrollingThreadRenderUpdateSyncEnd,
     95    ScrollingThreadDisplayDidRefreshStart,
     96    ScrollingThreadDisplayDidRefreshEnd,
    9397
    9498    WebKitRange = 10000,
  • trunk/Source/WebCore/ChangeLog

    r261984 r261985  
     12020-05-20  Simon Fraser  <simon.fraser@apple.com>
     2
     3        [macOS] Scrolling synchronization part 1: Have the scrolling thread wait half a frame for the main thread to complete the rendering update
     4        https://bugs.webkit.org/show_bug.cgi?id=212168
     5
     6        Reviewed by Tim Horton.
     7
     8        Currently the scrolling thread is a free-running thread that moves layers around in response
     9        to wheel events, and asynchronously posts data about scrolled layers back to the main thread.
     10        That results in an almost guaranteed lack of synchronization between the displayed layer
     11        positions, and the web-exposed values for scroll position (element.scrollTop, window.pageYOffset etc).
     12        This is a frequent source of stuttering or jumpy web content when scrolling.
     13
     14        The first step to fixing this is to synchronize the scrolling thread layer positions
     15        and the main thread state for the case where the main thread is responsive enough to
     16        render once per frame. This is achieved as follow:
     17            - When the main thread is starting a rendering update, Page::updateRendering() informs
     18              the scrolling tree via ScrollingCoordinatorMac::willStartRenderingUpdate(). This
     19              atomically waits for the scrolling thread to take the m_treeMutex (via a BinarySemaphore)
     20              and starts waiting on the m_stateCondition Condition. Now the main thread pulls the
     21              state of the scrolling tree via synchronizeStateFromScrollingTree() and uses it for
     22              the rendering update.
     23            - If the rendering update finishes within half a frame (8ms), then m_stateCondition
     24              is released, and the scrolling thread assumes that the main thread is going to
     25              commit layers rapidly enough to preserve 60fps scrolling.
     26            - If the rendering update takes too long, m_stateCondition times out, and the scrolling
     27              thread applies layer positions, triggering a CA commit on that thread.
     28
     29        We no longer apply layer positions directly when handling wheel events.
     30
     31        synchronizeStateFromScrollingTree() has to only pull state from nodes that have moved on the scrolling thread,
     32        so track that via ScrollingTreeScrollingNode::scrolledSinceLastCommit() and adjust the visitor function to
     33        make it available during scrolling tree traversal.
     34
     35        * page/Page.cpp:
     36        (WebCore::Page::updateRendering):
     37        (WebCore::Page::finalizeRenderingUpdate):
     38        * page/scrolling/AsyncScrollingCoordinator.cpp:
     39        (WebCore::AsyncScrollingCoordinator::synchronizeStateFromScrollingTree):
     40        * page/scrolling/AsyncScrollingCoordinator.h:
     41        * page/scrolling/ScrollingCoordinator.h:
     42        (WebCore::ScrollingCoordinator::willStartRenderingUpdate):
     43        (WebCore::ScrollingCoordinator::didCompleteRenderingUpdate):
     44        (WebCore::ScrollingCoordinator::synchronizeStateFromScrollingTree): Deleted.
     45        * page/scrolling/ScrollingTree.cpp:
     46        (WebCore::ScrollingTree::handleWheelEvent):
     47        (WebCore::ScrollingTree::traverseScrollingTreeRecursive):
     48        (WebCore::ScrollingTree::commitTreeState):
     49        (WebCore::ScrollingTree::updateTreeFromStateNodeRecursive):
     50        (WebCore::ScrollingTree::applyLayerPositionsInternal):
     51        (WebCore::ScrollingTree::nominalFramesPerSecond):
     52        * page/scrolling/ScrollingTree.h:
     53        * page/scrolling/ScrollingTreeNode.h:
     54        (WebCore::ScrollingTreeNode::didCompleteCommitForNode):
     55        * page/scrolling/ScrollingTreeScrollingNode.cpp:
     56        (WebCore::ScrollingTreeScrollingNode::didCompleteCommitForNode):
     57        (WebCore::ScrollingTreeScrollingNode::currentScrollPositionChanged):
     58        * page/scrolling/ScrollingTreeScrollingNode.h:
     59        * page/scrolling/ThreadedScrollingTree.cpp:
     60        (WebCore::ThreadedScrollingTree::willStartRenderingUpdate):
     61        (WebCore::ThreadedScrollingTree::maxAllowableRenderingUpdateDurationForSynchronization):
     62        (WebCore::ThreadedScrollingTree::waitForRenderingUpdateCompletionOrTimeout):
     63        (WebCore::ThreadedScrollingTree::didCompleteRenderingUpdate):
     64        (WebCore::ThreadedScrollingTree::displayDidRefreshOnScrollingThread):
     65        * page/scrolling/ThreadedScrollingTree.h:
     66        (WebCore::ThreadedScrollingTree::treeMutex):
     67        * page/scrolling/mac/ScrollingCoordinatorMac.h:
     68        * page/scrolling/mac/ScrollingCoordinatorMac.mm:
     69        (WebCore::ScrollingCoordinatorMac::willStartRenderingUpdate):
     70        (WebCore::ScrollingCoordinatorMac::didCompleteRenderingUpdate):
     71
    1722020-05-20  Chris Fleizach  <cfleizach@apple.com>
    273
  • trunk/Source/WebCore/page/Page.cpp

    r261948 r261985  
    13611361    layoutIfNeeded();
    13621362
     1363#if ENABLE(ASYNC_SCROLLING)
     1364    if (auto* scrollingCoordinator = this->scrollingCoordinator())
     1365        scrollingCoordinator->willStartRenderingUpdate();
     1366#endif
     1367
    13631368    // Timestamps should not change while serving the rendering update steps.
    13641369    Vector<WeakPtr<Document>> initialDocuments;
     
    14791484        if (flags.contains(FinalizeRenderingUpdateFlags::ApplyScrollingTreeLayerPositions))
    14801485            scrollingCoordinator->applyScrollingTreeLayerPositions();
     1486           
     1487        scrollingCoordinator->didCompleteRenderingUpdate();
    14811488    }
    14821489#endif
  • trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp

    r261948 r261985  
    297297    ASSERT(isMainThread());
    298298
    299     m_scrollingTree->traverseScrollingTree([&](ScrollingNodeID nodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin) {
    300         if (scrollPosition) {
     299    m_scrollingTree->traverseScrollingTree([&](ScrollingNodeID nodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool scrolledSinceLastCommit) {
     300        if (scrollPosition && scrolledSinceLastCommit) {
    301301            LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::synchronizeStateFromScrollingTree - node " << nodeID << " scroll position " << scrollPosition);
    302302            updateScrollPositionAfterAsyncScroll(nodeID, scrollPosition.value(), layoutViewportOrigin, ScrollType::User, ScrollingLayerPositionAction::Set);
  • trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h

    r261948 r261985  
    8383    WEBCORE_EXPORT String scrollingTreeAsText(ScrollingStateTreeAsTextBehavior = ScrollingStateTreeAsTextBehaviorNormal) const override;
    8484    WEBCORE_EXPORT void willCommitTree() override;
     85    void synchronizeStateFromScrollingTree();
    8586
    8687    bool eventTrackingRegionsDirty() const { return m_eventTrackingRegionsDirty; }
     
    103104
    104105    WEBCORE_EXPORT void applyScrollingTreeLayerPositions() override;
    105     WEBCORE_EXPORT void synchronizeStateFromScrollingTree() override;
    106106
    107107    WEBCORE_EXPORT ScrollingNodeID createNode(ScrollingNodeType, ScrollingNodeID newNodeID) override;
  • trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h

    r261948 r261985  
    114114    virtual void applyScrollingTreeLayerPositions() { }
    115115
    116     // Takes scroll positions from the scrolling tree and applies them to ScrollableAreas.
    117     virtual void synchronizeStateFromScrollingTree() { }
     116    virtual void willStartRenderingUpdate() { }
     117    virtual void didCompleteRenderingUpdate() { }
    118118
    119119#if ENABLE(KINETIC_SCROLLING)
  • trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp

    r261948 r261985  
    159159    }();
    160160
    161     if (result == ScrollingEventResult::DidHandleEvent)
    162         applyLayerPositionsInternal();
    163    
    164161    return result;
    165162}
     
    188185void ScrollingTree::traverseScrollingTreeRecursive(ScrollingTreeNode& node, const VisitorFunction& visitorFunction)
    189186{
     187    bool scrolledSinceLastCommit = false;
    190188    Optional<FloatPoint> scrollPosition;
    191     if (is<ScrollingTreeScrollingNode>(node))
    192         scrollPosition = downcast<ScrollingTreeScrollingNode>(node).currentScrollPosition();
     189    if (is<ScrollingTreeScrollingNode>(node)) {
     190        auto& scrollingNode = downcast<ScrollingTreeScrollingNode>(node);
     191        scrollPosition = scrollingNode.currentScrollPosition();
     192        scrolledSinceLastCommit = scrollingNode.scrolledSinceLastCommit();
     193    }
    193194
    194195    Optional<FloatPoint> layoutViewportOrigin;
     
    196197        layoutViewportOrigin = downcast<ScrollingTreeFrameScrollingNode>(node).layoutViewport().location();
    197198
    198     visitorFunction(node.scrollingNodeID(), node.nodeType(), scrollPosition, layoutViewportOrigin);
     199    visitorFunction(node.scrollingNodeID(), node.nodeType(), scrollPosition, layoutViewportOrigin, scrolledSinceLastCommit);
    199200
    200201    for (auto& child : node.children())
     
    218219
    219220    bool rootStateNodeChanged = scrollingStateTree->hasNewRootStateNode();
    220    
     221
    221222    LOG(ScrollingTree, "\nScrollingTree %p commitTreeState", this);
    222    
     223
    223224    auto* rootNode = scrollingStateTree->rootStateNode();
    224225    if (rootNode
     
    328329
    329330    node->commitStateAfterChildren(*stateNode);
    330    
     331    node->didCompleteCommitForNode();
     332
    331333#if ENABLE(SCROLLING_THREAD)
    332334    if (is<ScrollingTreeScrollingNode>(*node) && !downcast<ScrollingTreeScrollingNode>(*node).synchronousScrollingReasons().isEmpty())
     
    355357void ScrollingTree::applyLayerPositionsInternal()
    356358{
     359    ASSERT(m_treeMutex.isLocked());
    357360    if (!m_rootNode)
    358361        return;
     
    539542    LockHolder locker(m_treeStateMutex);
    540543    return m_treeState.displayID;
     544}
     545
     546Optional<unsigned> ScrollingTree::nominalFramesPerSecond()
     547{
     548    LockHolder locker(m_treeStateMutex);
     549    return m_treeState.nominalFramesPerSecond;
    541550}
    542551
  • trunk/Source/WebCore/page/scrolling/ScrollingTree.h

    r261948 r261985  
    9191    WEBCORE_EXPORT ScrollingTreeNode* nodeForID(ScrollingNodeID) const;
    9292
    93     using VisitorFunction = WTF::Function<void (ScrollingNodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin)>;
     93    using VisitorFunction = WTF::Function<void (ScrollingNodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool scrolledSinceLastCommit)>;
    9494    void traverseScrollingTree(VisitorFunction&&);
    9595
     
    189189    WEBCORE_EXPORT virtual ScrollingEventResult handleWheelEvent(const PlatformWheelEvent&);
    190190
     191    Optional<unsigned> nominalFramesPerSecond();
     192
     193    void applyLayerPositionsInternal();
     194    Lock m_treeMutex; // Protects the scrolling tree.
     195
    191196private:
    192197    void updateTreeFromStateNodeRecursive(const ScrollingStateNode*, struct CommitTreeState&);
    193198    virtual void propagateSynchronousScrollingReasons(const HashSet<ScrollingNodeID>&) { }
    194199
    195     void applyLayerPositionsInternal();
    196 
    197200    void applyLayerPositionsRecursive(ScrollingTreeNode&);
    198201    void notifyRelatedNodesRecursive(ScrollingTreeNode&);
     
    202205    WEBCORE_EXPORT virtual OptionSet<EventListenerRegionType> eventListenerRegionTypesForPoint(FloatPoint) const;
    203206    virtual void receivedWheelEvent(const PlatformWheelEvent&) { }
    204 
    205     Lock m_treeMutex; // Protects the scrolling tree.
    206207
    207208    RefPtr<ScrollingTreeFrameScrollingNode> m_rootNode;
  • trunk/Source/WebCore/page/scrolling/ScrollingTreeNode.h

    r257268 r261985  
    6161    virtual void commitStateBeforeChildren(const ScrollingStateNode&) = 0;
    6262    virtual void commitStateAfterChildren(const ScrollingStateNode&) { }
     63    virtual void didCompleteCommitForNode() { }
    6364
    6465    ScrollingTreeNode* parent() const { return m_parent; }
  • trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp

    r261849 r261985  
    125125}
    126126
     127void ScrollingTreeScrollingNode::didCompleteCommitForNode()
     128{
     129    m_scrolledSinceLastCommit = false;
     130}
     131
    127132bool ScrollingTreeScrollingNode::isLatchedNode() const
    128133{
     
    251256{
    252257    scrollingTree().scrollingTreeNodeDidScroll(*this);
     258    m_scrolledSinceLastCommit = true;
    253259}
    254260
  • trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h

    r261132 r261985  
    5353    void commitStateBeforeChildren(const ScrollingStateNode&) override;
    5454    void commitStateAfterChildren(const ScrollingStateNode&) override;
     55    void didCompleteCommitForNode() final;
    5556
    5657    virtual bool canHandleWheelEvent(const PlatformWheelEvent&) const;
     
    104105
    105106    bool eventCanScrollContents(const PlatformWheelEvent&) const;
     107   
     108    bool scrolledSinceLastCommit() const { return m_scrolledSinceLastCommit; }
    106109
    107110    const LayerRepresentation& scrollContainerLayer() const { return m_scrollContainerLayer; }
     
    163166#endif
    164167    bool m_isFirstCommit { true };
     168    bool m_scrolledSinceLastCommit { false };
    165169
    166170    LayerRepresentation m_scrollContainerLayer;
  • trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp

    r261876 r261985  
    3939#include <wtf/RunLoop.h>
    4040#include <wtf/SetForScope.h>
     41#include <wtf/SystemTracing.h>
    4142#include <wtf/text/TextStream.h>
     43#include <wtf/threads/BinarySemaphore.h>
    4244
    4345namespace WebCore {
     
    203205#endif
    204206
     207void ThreadedScrollingTree::willStartRenderingUpdate()
     208{
     209    ASSERT(isMainThread());
     210
     211    tracePoint(ScrollingThreadRenderUpdateSyncStart);
     212
     213    // Wait for the scrolling thread to acquire m_treeMutex. This ensures that any pending wheel events are processed.
     214    BinarySemaphore semaphore;
     215    ScrollingThread::dispatch([protectedThis = makeRef(*this), &semaphore]() {
     216        LockHolder treeLocker(protectedThis->m_treeMutex);
     217        semaphore.signal();
     218        protectedThis->waitForRenderingUpdateCompletionOrTimeout();
     219    });
     220    semaphore.wait();
     221    m_state = SynchronizationState::InRenderingUpdate;
     222}
     223
     224Seconds ThreadedScrollingTree::maxAllowableRenderingUpdateDurationForSynchronization()
     225{
     226    constexpr double allowableFrameFraction = 0.5;
     227    auto displayFPS = nominalFramesPerSecond().valueOr(60);
     228    Seconds frameDuration = 1_s / (double)displayFPS;
     229    return allowableFrameFraction * frameDuration;
     230}
     231
     232// This code allows the main thread about half a frame to complete its rendering udpate. If the main thread
     233// is responsive (i.e. managing to render every frame), then we expect to get a didCompleteRenderingUpdate()
     234// within 8ms of willStartRenderingUpdate(). We time this via m_stateCondition, which blocks the scrolling
     235// thread (with m_treeMutex locked at the start and end) so that we don't handle wheel events while waiting.
     236// If the condition times out, we know the main thread is being slow, and allow the scrolling thread to
     237// commit layer positions.
     238void ThreadedScrollingTree::waitForRenderingUpdateCompletionOrTimeout()
     239{
     240    ASSERT(ScrollingThread::isCurrentThread());
     241    ASSERT(m_treeMutex.isLocked());
     242
     243    auto startTime = MonotonicTime::now();
     244    auto timeoutTime = startTime + maxAllowableRenderingUpdateDurationForSynchronization();
     245
     246    bool becameIdle = m_stateCondition.waitUntil(m_treeMutex, timeoutTime, [&] {
     247        return m_state == SynchronizationState::Idle;
     248    });
     249
     250    ASSERT(m_treeMutex.isLocked());
     251
     252    if (!becameIdle) {
     253        m_state = SynchronizationState::Desynchronized;
     254        // At this point we know the main thread is taking too long in the rendering update,
     255        // so we give up trying to sync with the main thread and update layers here on the scrolling thread.
     256        applyLayerPositionsInternal();
     257        tracePoint(ScrollingThreadRenderUpdateSyncEnd, 1);
     258    } else
     259        tracePoint(ScrollingThreadRenderUpdateSyncEnd);
     260}
     261
     262void ThreadedScrollingTree::didCompleteRenderingUpdate()
     263{
     264    ASSERT(isMainThread());
     265    LockHolder treeLocker(m_treeMutex);
     266
     267    if (m_state == SynchronizationState::InRenderingUpdate)
     268        m_stateCondition.notifyOne();
     269
     270    m_state = SynchronizationState::Idle;
     271}
     272
     273void ThreadedScrollingTree::displayDidRefreshOnScrollingThread()
     274{
     275    TraceScope tracingScope(ScrollingThreadDisplayDidRefreshStart, ScrollingThreadDisplayDidRefreshEnd);
     276    ASSERT(ScrollingThread::isCurrentThread());
     277
     278    LockHolder treeLocker(m_treeMutex);
     279
     280    if (m_state != SynchronizationState::Idle)
     281        applyLayerPositionsInternal();
     282
     283    switch (m_state) {
     284    case SynchronizationState::Idle: {
     285        m_state = SynchronizationState::WaitingForRenderingUpdate;
     286        break;
     287    }
     288    case SynchronizationState::WaitingForRenderingUpdate:
     289    case SynchronizationState::InRenderingUpdate:
     290    case SynchronizationState::Desynchronized:
     291        break;
     292    }
     293}
     294
    205295void ThreadedScrollingTree::displayDidRefresh(PlatformDisplayID displayID)
    206296{
     
    217307}
    218308
    219 void ThreadedScrollingTree::displayDidRefreshOnScrollingThread()
    220 {
    221     ASSERT(ScrollingThread::isCurrentThread());
    222 }
    223 
    224309} // namespace WebCore
    225310
  • trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h

    r261876 r261985  
    5858    WEBCORE_EXPORT void displayDidRefresh(PlatformDisplayID);
    5959
     60    void willStartRenderingUpdate();
     61    void didCompleteRenderingUpdate();
     62
     63    Lock& treeMutex() { return m_treeMutex; }
     64
    6065protected:
    6166    explicit ThreadedScrollingTree(AsyncScrollingCoordinator&);
     
    8085
    8186    void displayDidRefreshOnScrollingThread();
     87    void waitForRenderingUpdateCompletionOrTimeout();
     88   
     89    Seconds maxAllowableRenderingUpdateDurationForSynchronization();
    8290
    8391    RefPtr<AsyncScrollingCoordinator> m_scrollingCoordinator;
     92
     93    enum class SynchronizationState : uint8_t {
     94        Idle,
     95        WaitingForRenderingUpdate,
     96        InRenderingUpdate,
     97        Desynchronized,
     98    };
     99
     100    SynchronizationState m_state { SynchronizationState::Idle };
     101    Condition m_stateCondition;
    84102};
    85103
  • trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h

    r261539 r261985  
    4747    void scheduleTreeStateCommit() final;
    4848
     49    void willStartRenderingUpdate() final;
     50    void didCompleteRenderingUpdate() final;
     51
    4952    void updateTiledScrollingIndicator();
    5053
  • trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm

    r261849 r261985  
    111111}
    112112
     113void ScrollingCoordinatorMac::willStartRenderingUpdate()
     114{
     115    RefPtr<ThreadedScrollingTree> threadedScrollingTree = downcast<ThreadedScrollingTree>(scrollingTree());
     116    threadedScrollingTree->willStartRenderingUpdate();
     117    synchronizeStateFromScrollingTree();
     118}
     119
     120void ScrollingCoordinatorMac::didCompleteRenderingUpdate()
     121{
     122    downcast<ThreadedScrollingTree>(scrollingTree())->didCompleteRenderingUpdate();
     123}
     124
    113125void ScrollingCoordinatorMac::updateTiledScrollingIndicator()
    114126{
  • trunk/Tools/ChangeLog

    r261972 r261985  
     12020-05-20  Simon Fraser  <simon.fraser@apple.com>
     2
     3        [macOS] Scrolling synchronization part 1: Have the scrolling thread wait half a frame for the main thread to complete the rendering update
     4        https://bugs.webkit.org/show_bug.cgi?id=212168
     5
     6        Reviewed by Tim Horton.
     7
     8        Some new trace points for scrolling thread activity.
     9
     10        * Tracing/SystemTracePoints.plist:
     11
    1122020-05-20  Wenson Hsieh  <wenson_hsieh@apple.com>
    213
  • trunk/Tools/Tracing/SystemTracePoints.plist

    r257898 r261985  
    340340             <dict>
    341341                 <key>Name</key>
     342                 <string>Scrolling Sync</string>
     343                 <key>Type</key>
     344                 <string>Interval</string>
     345                 <key>Component</key>
     346                 <string>47</string>
     347                 <key>CodeBegin</key>
     348                 <string>5040</string>
     349                 <key>CodeEnd</key>
     350                 <string>5041</string>
     351             </dict>
     352             <dict>
     353                 <key>Name</key>
     354                 <string>Scrolling Thread DisplayDidRefresh</string>
     355                 <key>Type</key>
     356                 <string>Interval</string>
     357                 <key>Component</key>
     358                 <string>47</string>
     359                 <key>CodeBegin</key>
     360                 <string>5042</string>
     361                 <key>CodeEnd</key>
     362                 <string>5043</string>
     363             </dict>
     364             <dict>
     365                 <key>Name</key>
    342366                 <string>Paint WebHTMLView</string>
    343367                 <key>Type</key>
Note: See TracChangeset for help on using the changeset viewer.