Diff
Modified: trunk/Source/WTF/ChangeLog (261984 => 261985)
--- trunk/Source/WTF/ChangeLog 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WTF/ChangeLog 2020-05-21 06:47:24 UTC (rev 261985)
@@ -1,3 +1,14 @@
+2020-05-20 Simon Fraser <[email protected]>
+
+ [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.
+
+ Some new trace points for scrolling thread activity.
+
+ * wtf/SystemTracing.h:
+
2020-05-20 Tim Horton <[email protected]>
WKMouseGestureRecognizer should be implemented without using UIKit internals
Modified: trunk/Source/WTF/wtf/SystemTracing.h (261984 => 261985)
--- trunk/Source/WTF/wtf/SystemTracing.h 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WTF/wtf/SystemTracing.h 2020-05-21 06:47:24 UTC (rev 261985)
@@ -90,6 +90,10 @@
ParseHTMLEnd,
DisplayListReplayStart,
DisplayListReplayEnd,
+ ScrollingThreadRenderUpdateSyncStart,
+ ScrollingThreadRenderUpdateSyncEnd,
+ ScrollingThreadDisplayDidRefreshStart,
+ ScrollingThreadDisplayDidRefreshEnd,
WebKitRange = 10000,
WebHTMLViewPaintStart,
Modified: trunk/Source/WebCore/ChangeLog (261984 => 261985)
--- trunk/Source/WebCore/ChangeLog 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/ChangeLog 2020-05-21 06:47:24 UTC (rev 261985)
@@ -1,3 +1,74 @@
+2020-05-20 Simon Fraser <[email protected]>
+
+ [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.
+
+ 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):
+
2020-05-20 Chris Fleizach <[email protected]>
REGRESSION (iOS 13.4.1): SpeechSynthesisUtterance.onend event won't fire on cancel().
Modified: trunk/Source/WebCore/page/Page.cpp (261984 => 261985)
--- trunk/Source/WebCore/page/Page.cpp 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/Page.cpp 2020-05-21 06:47:24 UTC (rev 261985)
@@ -1360,6 +1360,11 @@
layoutIfNeeded();
+#if ENABLE(ASYNC_SCROLLING)
+ if (auto* scrollingCoordinator = this->scrollingCoordinator())
+ scrollingCoordinator->willStartRenderingUpdate();
+#endif
+
// Timestamps should not change while serving the rendering update steps.
Vector<WeakPtr<Document>> initialDocuments;
forEachDocument([&initialDocuments] (Document& document) {
@@ -1478,6 +1483,8 @@
scrollingCoordinator->commitTreeStateIfNeeded();
if (flags.contains(FinalizeRenderingUpdateFlags::ApplyScrollingTreeLayerPositions))
scrollingCoordinator->applyScrollingTreeLayerPositions();
+
+ scrollingCoordinator->didCompleteRenderingUpdate();
}
#endif
}
Modified: trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp 2020-05-21 06:47:24 UTC (rev 261985)
@@ -296,8 +296,8 @@
{
ASSERT(isMainThread());
- m_scrollingTree->traverseScrollingTree([&](ScrollingNodeID nodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin) {
- if (scrollPosition) {
+ m_scrollingTree->traverseScrollingTree([&](ScrollingNodeID nodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool scrolledSinceLastCommit) {
+ if (scrollPosition && scrolledSinceLastCommit) {
LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::synchronizeStateFromScrollingTree - node " << nodeID << " scroll position " << scrollPosition);
updateScrollPositionAfterAsyncScroll(nodeID, scrollPosition.value(), layoutViewportOrigin, ScrollType::User, ScrollingLayerPositionAction::Set);
}
Modified: trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h 2020-05-21 06:47:24 UTC (rev 261985)
@@ -82,6 +82,7 @@
WEBCORE_EXPORT String scrollingStateTreeAsText(ScrollingStateTreeAsTextBehavior = ScrollingStateTreeAsTextBehaviorNormal) const override;
WEBCORE_EXPORT String scrollingTreeAsText(ScrollingStateTreeAsTextBehavior = ScrollingStateTreeAsTextBehaviorNormal) const override;
WEBCORE_EXPORT void willCommitTree() override;
+ void synchronizeStateFromScrollingTree();
bool eventTrackingRegionsDirty() const { return m_eventTrackingRegionsDirty; }
@@ -102,7 +103,6 @@
WEBCORE_EXPORT bool requestScrollPositionUpdate(ScrollableArea&, const IntPoint&, ScrollType, ScrollClamping) override;
WEBCORE_EXPORT void applyScrollingTreeLayerPositions() override;
- WEBCORE_EXPORT void synchronizeStateFromScrollingTree() override;
WEBCORE_EXPORT ScrollingNodeID createNode(ScrollingNodeType, ScrollingNodeID newNodeID) override;
WEBCORE_EXPORT ScrollingNodeID insertNode(ScrollingNodeType, ScrollingNodeID newNodeID, ScrollingNodeID parentID, size_t childIndex) override;
Modified: trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h 2020-05-21 06:47:24 UTC (rev 261985)
@@ -113,8 +113,8 @@
// Traverses the scrolling tree, setting layer positions to represent the current scrolled state.
virtual void applyScrollingTreeLayerPositions() { }
- // Takes scroll positions from the scrolling tree and applies them to ScrollableAreas.
- virtual void synchronizeStateFromScrollingTree() { }
+ virtual void willStartRenderingUpdate() { }
+ virtual void didCompleteRenderingUpdate() { }
#if ENABLE(KINETIC_SCROLLING)
// Dispatched by the scrolling tree during handleWheelEvent. This is required as long as scrollbars are painted on the main thread.
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp 2020-05-21 06:47:24 UTC (rev 261985)
@@ -158,9 +158,6 @@
return ScrollingEventResult::DidNotHandleEvent;
}();
- if (result == ScrollingEventResult::DidHandleEvent)
- applyLayerPositionsInternal();
-
return result;
}
@@ -187,15 +184,19 @@
void ScrollingTree::traverseScrollingTreeRecursive(ScrollingTreeNode& node, const VisitorFunction& visitorFunction)
{
+ bool scrolledSinceLastCommit = false;
Optional<FloatPoint> scrollPosition;
- if (is<ScrollingTreeScrollingNode>(node))
- scrollPosition = downcast<ScrollingTreeScrollingNode>(node).currentScrollPosition();
+ if (is<ScrollingTreeScrollingNode>(node)) {
+ auto& scrollingNode = downcast<ScrollingTreeScrollingNode>(node);
+ scrollPosition = scrollingNode.currentScrollPosition();
+ scrolledSinceLastCommit = scrollingNode.scrolledSinceLastCommit();
+ }
Optional<FloatPoint> layoutViewportOrigin;
if (is<ScrollingTreeFrameScrollingNode>(node))
layoutViewportOrigin = downcast<ScrollingTreeFrameScrollingNode>(node).layoutViewport().location();
- visitorFunction(node.scrollingNodeID(), node.nodeType(), scrollPosition, layoutViewportOrigin);
+ visitorFunction(node.scrollingNodeID(), node.nodeType(), scrollPosition, layoutViewportOrigin, scrolledSinceLastCommit);
for (auto& child : node.children())
traverseScrollingTreeRecursive(child.get(), visitorFunction);
@@ -217,9 +218,9 @@
LockHolder locker(m_treeMutex);
bool rootStateNodeChanged = scrollingStateTree->hasNewRootStateNode();
-
+
LOG(ScrollingTree, "\nScrollingTree %p commitTreeState", this);
-
+
auto* rootNode = scrollingStateTree->rootStateNode();
if (rootNode
&& (rootStateNodeChanged
@@ -327,7 +328,8 @@
}
node->commitStateAfterChildren(*stateNode);
-
+ node->didCompleteCommitForNode();
+
#if ENABLE(SCROLLING_THREAD)
if (is<ScrollingTreeScrollingNode>(*node) && !downcast<ScrollingTreeScrollingNode>(*node).synchronousScrollingReasons().isEmpty())
state.synchronousScrollingNodes.add(nodeID);
@@ -354,6 +356,7 @@
void ScrollingTree::applyLayerPositionsInternal()
{
+ ASSERT(m_treeMutex.isLocked());
if (!m_rootNode)
return;
@@ -540,6 +543,12 @@
return m_treeState.displayID;
}
+Optional<unsigned> ScrollingTree::nominalFramesPerSecond()
+{
+ LockHolder locker(m_treeStateMutex);
+ return m_treeState.nominalFramesPerSecond;
+}
+
void ScrollingTree::setScrollingPerformanceLoggingEnabled(bool flag)
{
m_scrollingPerformanceLoggingEnabled = flag;
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.h (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/ScrollingTree.h 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.h 2020-05-21 06:47:24 UTC (rev 261985)
@@ -90,7 +90,7 @@
WEBCORE_EXPORT ScrollingTreeNode* nodeForID(ScrollingNodeID) const;
- using VisitorFunction = WTF::Function<void (ScrollingNodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin)>;
+ using VisitorFunction = WTF::Function<void (ScrollingNodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool scrolledSinceLastCommit)>;
void traverseScrollingTree(VisitorFunction&&);
// Called after a scrolling tree node has handled a scroll and updated its layers.
@@ -188,12 +188,15 @@
WEBCORE_EXPORT virtual ScrollingEventResult handleWheelEvent(const PlatformWheelEvent&);
+ Optional<unsigned> nominalFramesPerSecond();
+
+ void applyLayerPositionsInternal();
+ Lock m_treeMutex; // Protects the scrolling tree.
+
private:
void updateTreeFromStateNodeRecursive(const ScrollingStateNode*, struct CommitTreeState&);
virtual void propagateSynchronousScrollingReasons(const HashSet<ScrollingNodeID>&) { }
- void applyLayerPositionsInternal();
-
void applyLayerPositionsRecursive(ScrollingTreeNode&);
void notifyRelatedNodesRecursive(ScrollingTreeNode&);
void traverseScrollingTreeRecursive(ScrollingTreeNode&, const VisitorFunction&);
@@ -202,8 +205,6 @@
WEBCORE_EXPORT virtual OptionSet<EventListenerRegionType> eventListenerRegionTypesForPoint(FloatPoint) const;
virtual void receivedWheelEvent(const PlatformWheelEvent&) { }
- Lock m_treeMutex; // Protects the scrolling tree.
-
RefPtr<ScrollingTreeFrameScrollingNode> m_rootNode;
using ScrollingTreeNodeMap = HashMap<ScrollingNodeID, RefPtr<ScrollingTreeNode>>;
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeNode.h (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/ScrollingTreeNode.h 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeNode.h 2020-05-21 06:47:24 UTC (rev 261985)
@@ -60,6 +60,7 @@
virtual void commitStateBeforeChildren(const ScrollingStateNode&) = 0;
virtual void commitStateAfterChildren(const ScrollingStateNode&) { }
+ virtual void didCompleteCommitForNode() { }
ScrollingTreeNode* parent() const { return m_parent; }
void setParent(ScrollingTreeNode* parent) { m_parent = parent; }
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp 2020-05-21 06:47:24 UTC (rev 261985)
@@ -124,6 +124,11 @@
m_isFirstCommit = false;
}
+void ScrollingTreeScrollingNode::didCompleteCommitForNode()
+{
+ m_scrolledSinceLastCommit = false;
+}
+
bool ScrollingTreeScrollingNode::isLatchedNode() const
{
return scrollingTree().latchedNodeID() == scrollingNodeID();
@@ -250,6 +255,7 @@
void ScrollingTreeScrollingNode::currentScrollPositionChanged()
{
scrollingTree().scrollingTreeNodeDidScroll(*this);
+ m_scrolledSinceLastCommit = true;
}
bool ScrollingTreeScrollingNode::scrollPositionAndLayoutViewportMatch(const FloatPoint& position, Optional<FloatRect>)
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h 2020-05-21 06:47:24 UTC (rev 261985)
@@ -52,6 +52,7 @@
void commitStateBeforeChildren(const ScrollingStateNode&) override;
void commitStateAfterChildren(const ScrollingStateNode&) override;
+ void didCompleteCommitForNode() final;
virtual bool canHandleWheelEvent(const PlatformWheelEvent&) const;
virtual ScrollingEventResult handleWheelEvent(const PlatformWheelEvent&);
@@ -103,6 +104,8 @@
bool useDarkAppearanceForScrollbars() const { return m_scrollableAreaParameters.useDarkAppearanceForScrollbars; }
bool eventCanScrollContents(const PlatformWheelEvent&) const;
+
+ bool scrolledSinceLastCommit() const { return m_scrolledSinceLastCommit; }
const LayerRepresentation& scrollContainerLayer() const { return m_scrollContainerLayer; }
const LayerRepresentation& scrolledContentsLayer() const { return m_scrolledContentsLayer; }
@@ -162,6 +165,7 @@
OptionSet<SynchronousScrollingReason> m_synchronousScrollingReasons;
#endif
bool m_isFirstCommit { true };
+ bool m_scrolledSinceLastCommit { false };
LayerRepresentation m_scrollContainerLayer;
LayerRepresentation m_scrolledContentsLayer;
Modified: trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp 2020-05-21 06:47:24 UTC (rev 261985)
@@ -38,7 +38,9 @@
#include "ScrollingTreeScrollingNode.h"
#include <wtf/RunLoop.h>
#include <wtf/SetForScope.h>
+#include <wtf/SystemTracing.h>
#include <wtf/text/TextStream.h>
+#include <wtf/threads/BinarySemaphore.h>
namespace WebCore {
@@ -202,6 +204,94 @@
}
#endif
+void ThreadedScrollingTree::willStartRenderingUpdate()
+{
+ ASSERT(isMainThread());
+
+ tracePoint(ScrollingThreadRenderUpdateSyncStart);
+
+ // Wait for the scrolling thread to acquire m_treeMutex. This ensures that any pending wheel events are processed.
+ BinarySemaphore semaphore;
+ ScrollingThread::dispatch([protectedThis = makeRef(*this), &semaphore]() {
+ LockHolder treeLocker(protectedThis->m_treeMutex);
+ semaphore.signal();
+ protectedThis->waitForRenderingUpdateCompletionOrTimeout();
+ });
+ semaphore.wait();
+ m_state = SynchronizationState::InRenderingUpdate;
+}
+
+Seconds ThreadedScrollingTree::maxAllowableRenderingUpdateDurationForSynchronization()
+{
+ constexpr double allowableFrameFraction = 0.5;
+ auto displayFPS = nominalFramesPerSecond().valueOr(60);
+ Seconds frameDuration = 1_s / (double)displayFPS;
+ return allowableFrameFraction * frameDuration;
+}
+
+// This code allows the main thread about half a frame to complete its rendering udpate. If the main thread
+// is responsive (i.e. managing to render every frame), then we expect to get a didCompleteRenderingUpdate()
+// within 8ms of willStartRenderingUpdate(). We time this via m_stateCondition, which blocks the scrolling
+// thread (with m_treeMutex locked at the start and end) so that we don't handle wheel events while waiting.
+// If the condition times out, we know the main thread is being slow, and allow the scrolling thread to
+// commit layer positions.
+void ThreadedScrollingTree::waitForRenderingUpdateCompletionOrTimeout()
+{
+ ASSERT(ScrollingThread::isCurrentThread());
+ ASSERT(m_treeMutex.isLocked());
+
+ auto startTime = MonotonicTime::now();
+ auto timeoutTime = startTime + maxAllowableRenderingUpdateDurationForSynchronization();
+
+ bool becameIdle = m_stateCondition.waitUntil(m_treeMutex, timeoutTime, [&] {
+ return m_state == SynchronizationState::Idle;
+ });
+
+ ASSERT(m_treeMutex.isLocked());
+
+ if (!becameIdle) {
+ m_state = SynchronizationState::Desynchronized;
+ // At this point we know the main thread is taking too long in the rendering update,
+ // so we give up trying to sync with the main thread and update layers here on the scrolling thread.
+ applyLayerPositionsInternal();
+ tracePoint(ScrollingThreadRenderUpdateSyncEnd, 1);
+ } else
+ tracePoint(ScrollingThreadRenderUpdateSyncEnd);
+}
+
+void ThreadedScrollingTree::didCompleteRenderingUpdate()
+{
+ ASSERT(isMainThread());
+ LockHolder treeLocker(m_treeMutex);
+
+ if (m_state == SynchronizationState::InRenderingUpdate)
+ m_stateCondition.notifyOne();
+
+ m_state = SynchronizationState::Idle;
+}
+
+void ThreadedScrollingTree::displayDidRefreshOnScrollingThread()
+{
+ TraceScope tracingScope(ScrollingThreadDisplayDidRefreshStart, ScrollingThreadDisplayDidRefreshEnd);
+ ASSERT(ScrollingThread::isCurrentThread());
+
+ LockHolder treeLocker(m_treeMutex);
+
+ if (m_state != SynchronizationState::Idle)
+ applyLayerPositionsInternal();
+
+ switch (m_state) {
+ case SynchronizationState::Idle: {
+ m_state = SynchronizationState::WaitingForRenderingUpdate;
+ break;
+ }
+ case SynchronizationState::WaitingForRenderingUpdate:
+ case SynchronizationState::InRenderingUpdate:
+ case SynchronizationState::Desynchronized:
+ break;
+ }
+}
+
void ThreadedScrollingTree::displayDidRefresh(PlatformDisplayID displayID)
{
if (displayID != this->displayID())
@@ -216,11 +306,6 @@
#endif
}
-void ThreadedScrollingTree::displayDidRefreshOnScrollingThread()
-{
- ASSERT(ScrollingThread::isCurrentThread());
-}
-
} // namespace WebCore
#endif // ENABLE(ASYNC_SCROLLING) && ENABLE(SCROLLING_THREAD)
Modified: trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h 2020-05-21 06:47:24 UTC (rev 261985)
@@ -57,6 +57,11 @@
WEBCORE_EXPORT void displayDidRefresh(PlatformDisplayID);
+ void willStartRenderingUpdate();
+ void didCompleteRenderingUpdate();
+
+ Lock& treeMutex() { return m_treeMutex; }
+
protected:
explicit ThreadedScrollingTree(AsyncScrollingCoordinator&);
@@ -79,8 +84,21 @@
void propagateSynchronousScrollingReasons(const HashSet<ScrollingNodeID>&) override;
void displayDidRefreshOnScrollingThread();
+ void waitForRenderingUpdateCompletionOrTimeout();
+
+ Seconds maxAllowableRenderingUpdateDurationForSynchronization();
RefPtr<AsyncScrollingCoordinator> m_scrollingCoordinator;
+
+ enum class SynchronizationState : uint8_t {
+ Idle,
+ WaitingForRenderingUpdate,
+ InRenderingUpdate,
+ Desynchronized,
+ };
+
+ SynchronizationState m_state { SynchronizationState::Idle };
+ Condition m_stateCondition;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h 2020-05-21 06:47:24 UTC (rev 261985)
@@ -46,6 +46,9 @@
private:
void scheduleTreeStateCommit() final;
+ void willStartRenderingUpdate() final;
+ void didCompleteRenderingUpdate() final;
+
void updateTiledScrollingIndicator();
void startMonitoringWheelEvents(bool clearLatchingState) final;
Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm (261984 => 261985)
--- trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm 2020-05-21 06:47:24 UTC (rev 261985)
@@ -110,6 +110,18 @@
updateTiledScrollingIndicator();
}
+void ScrollingCoordinatorMac::willStartRenderingUpdate()
+{
+ RefPtr<ThreadedScrollingTree> threadedScrollingTree = downcast<ThreadedScrollingTree>(scrollingTree());
+ threadedScrollingTree->willStartRenderingUpdate();
+ synchronizeStateFromScrollingTree();
+}
+
+void ScrollingCoordinatorMac::didCompleteRenderingUpdate()
+{
+ downcast<ThreadedScrollingTree>(scrollingTree())->didCompleteRenderingUpdate();
+}
+
void ScrollingCoordinatorMac::updateTiledScrollingIndicator()
{
FrameView* frameView = m_page->mainFrame().view();
Modified: trunk/Tools/ChangeLog (261984 => 261985)
--- trunk/Tools/ChangeLog 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Tools/ChangeLog 2020-05-21 06:47:24 UTC (rev 261985)
@@ -1,3 +1,14 @@
+2020-05-20 Simon Fraser <[email protected]>
+
+ [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.
+
+ Some new trace points for scrolling thread activity.
+
+ * Tracing/SystemTracePoints.plist:
+
2020-05-20 Wenson Hsieh <[email protected]>
[iOS] Layout tests in editing/pasteboard sporadically crash
Modified: trunk/Tools/Tracing/SystemTracePoints.plist (261984 => 261985)
--- trunk/Tools/Tracing/SystemTracePoints.plist 2020-05-21 05:46:51 UTC (rev 261984)
+++ trunk/Tools/Tracing/SystemTracePoints.plist 2020-05-21 06:47:24 UTC (rev 261985)
@@ -339,6 +339,30 @@
</dict>
<dict>
<key>Name</key>
+ <string>Scrolling Sync</string>
+ <key>Type</key>
+ <string>Interval</string>
+ <key>Component</key>
+ <string>47</string>
+ <key>CodeBegin</key>
+ <string>5040</string>
+ <key>CodeEnd</key>
+ <string>5041</string>
+ </dict>
+ <dict>
+ <key>Name</key>
+ <string>Scrolling Thread DisplayDidRefresh</string>
+ <key>Type</key>
+ <string>Interval</string>
+ <key>Component</key>
+ <string>47</string>
+ <key>CodeBegin</key>
+ <string>5042</string>
+ <key>CodeEnd</key>
+ <string>5043</string>
+ </dict>
+ <dict>
+ <key>Name</key>
<string>Paint WebHTMLView</string>
<key>Type</key>
<string>Interval</string>