Title: [275440] trunk/Source
Revision
275440
Author
[email protected]
Date
2021-04-02 14:29:13 -0700 (Fri, 02 Apr 2021)

Log Message

Allow wheel events to trigger high frequency DisplayLinks
https://bugs.webkit.org/show_bug.cgi?id=224095

Reviewed by Sam Weinig.

Source/WebCore:

Adjust some logging so it's clear which process code is running in.

* platform/graphics/DisplayRefreshMonitor.cpp:
(WebCore::DisplayRefreshMonitor::displayLinkFired):
* platform/graphics/DisplayRefreshMonitorManager.cpp:
(WebCore::DisplayRefreshMonitorManager::ensureMonitorForDisplayID):

Source/WebKit:

When scrolling via wheel events, we may want to drive scrolling tree updates
(which are driven by EventDispatcher::displayWasRefreshed()) at a higher rate
than the main thread does rendering updates.

To support this, give DisplayLink a count of "full speed" clients, and when this count is
greater than zero, have DisplayLink::notifyObserversDisplayWasRefreshed() send
EventDispatcher IPC at full framerate, while passing a flag based on the usual
relevantForUpdateFrequency() about whether to update the main thread for a given update.

Allow DisplayLink connection info objects with non-zero fullSpeedUpdatesClientCount
to stick around, because that fullSpeedUpdatesClientCount needs to be stored for
connections that may not yet have observers.

Since DisplayLink might have info for connections with no observers, adjust the logic in
DisplayLink::notifyObserversDisplayWasRefreshed() to do the CVDisplayLinkStop
after traversing the observers.

The "full speed" client count is maintained by a HysteresisActivity on WebPageProxy,
whose impulse is wheel events. This replaces a singleton HysteresisActivity which
was used to determine whether IPC goes to EventDispatcher or the main thread of
the web process.

WebPageProxy needs to track the PlatformDisplayID for the screen that its view is on,
so it knows which DisplayLink to message.

* UIProcess/Cocoa/WebProcessPoolCocoa.mm:
(WebKit::WebProcessPool::setDisplayLinkForDisplayWantsFullSpeedUpdates):
* UIProcess/WebPageProxy.cpp:
(WebKit::m_wheelEventActivityHysteresis):
(WebKit::WebPageProxy::wheelEventHysteresisUpdated):
(WebKit::WebPageProxy::sendWheelEvent):
(WebKit::WebPageProxy::windowScreenDidChange):
(WebKit::ScrollingObserver::willSendWheelEvent): Deleted.
(WebKit::ScrollingObserver::ScrollingObserver): Deleted.
(WebKit::ScrollingObserver::singleton): Deleted.
* UIProcess/WebPageProxy.h:
* UIProcess/WebProcessPool.h:
* UIProcess/mac/DisplayLink.cpp:
(WebKit::DisplayLink::DisplayLink):
(WebKit::DisplayLink::~DisplayLink):
(WebKit::DisplayLink::addObserver):
(WebKit::DisplayLink::removeObserver):
(WebKit::DisplayLink::removeInfoForConnectionIfPossible):
(WebKit::DisplayLink::incrementFullSpeedRequestClientCount):
(WebKit::DisplayLink::decrementFullSpeedRequestClientCount):
(WebKit::DisplayLink::setPreferredFramesPerSecond):
(WebKit::DisplayLink::notifyObserversDisplayWasRefreshed):
* UIProcess/mac/DisplayLink.h:
* WebProcess/WebPage/EventDispatcher.cpp:
(WebKit::EventDispatcher::displayWasRefreshed):
* WebProcess/WebPage/EventDispatcher.h:
* WebProcess/WebPage/EventDispatcher.messages.in:
* WebProcess/WebPage/mac/DisplayRefreshMonitorMac.cpp:
(WebKit::DisplayRefreshMonitorMac::startNotificationMechanism):
(WebKit::DisplayRefreshMonitorMac::adjustPreferredFramesPerSecond):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (275439 => 275440)


--- trunk/Source/WebCore/ChangeLog	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebCore/ChangeLog	2021-04-02 21:29:13 UTC (rev 275440)
@@ -1,3 +1,17 @@
+2021-04-02  Simon Fraser  <[email protected]>
+
+        Allow wheel events to trigger high frequency DisplayLinks
+        https://bugs.webkit.org/show_bug.cgi?id=224095
+
+        Reviewed by Sam Weinig.
+
+        Adjust some logging so it's clear which process code is running in.
+
+        * platform/graphics/DisplayRefreshMonitor.cpp:
+        (WebCore::DisplayRefreshMonitor::displayLinkFired):
+        * platform/graphics/DisplayRefreshMonitorManager.cpp:
+        (WebCore::DisplayRefreshMonitorManager::ensureMonitorForDisplayID):
+
 2021-04-02  David Kilzer  <[email protected]>
 
         UBSan: AlternativeTextController::dismiss()/dismissSoon(): runtime error: load of value nnn, which is not a valid value for type 'bool'

Modified: trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitor.cpp (275439 => 275440)


--- trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitor.cpp	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitor.cpp	2021-04-02 21:29:13 UTC (rev 275440)
@@ -172,7 +172,7 @@
         if (!isPreviousFrameDone())
             return;
 
-        LOG_WITH_STREAM(DisplayLink, stream << "DisplayRefreshMonitor::displayLinkFired for display " << displayID() << " - scheduled " << isScheduled() << " unscheduledFireCount " << m_unscheduledFireCount << " of " << m_maxUnscheduledFireCount);
+        LOG_WITH_STREAM(DisplayLink, stream << "[Web] DisplayRefreshMonitor::displayLinkFired for display " << displayID() << " - scheduled " << isScheduled() << " unscheduledFireCount " << m_unscheduledFireCount << " of " << m_maxUnscheduledFireCount);
         if (firedAndReachedMaxUnscheduledFireCount()) {
             stopNotificationMechanism();
             return;

Modified: trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitorManager.cpp (275439 => 275440)


--- trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitorManager.cpp	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebCore/platform/graphics/DisplayRefreshMonitorManager.cpp	2021-04-02 21:29:13 UTC (rev 275440)
@@ -50,7 +50,7 @@
     if (!monitor)
         return nullptr;
 
-    LOG_WITH_STREAM(DisplayLink, stream << "DisplayRefreshMonitorManager::ensureMonitorForDisplayID() - created monitor " << monitor.get() << " for display " << displayID);
+    LOG_WITH_STREAM(DisplayLink, stream << "[Web] DisplayRefreshMonitorManager::ensureMonitorForDisplayID() - created monitor " << monitor.get() << " for display " << displayID);
     DisplayRefreshMonitor* result = monitor.get();
     m_monitors.append({ WTFMove(monitor) });
     return result;

Modified: trunk/Source/WebKit/ChangeLog (275439 => 275440)


--- trunk/Source/WebKit/ChangeLog	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/ChangeLog	2021-04-02 21:29:13 UTC (rev 275440)
@@ -1,3 +1,66 @@
+2021-04-01  Simon Fraser  <[email protected]>
+
+        Allow wheel events to trigger high frequency DisplayLinks
+        https://bugs.webkit.org/show_bug.cgi?id=224095
+
+        Reviewed by Sam Weinig.
+
+        When scrolling via wheel events, we may want to drive scrolling tree updates
+        (which are driven by EventDispatcher::displayWasRefreshed()) at a higher rate
+        than the main thread does rendering updates.
+
+        To support this, give DisplayLink a count of "full speed" clients, and when this count is
+        greater than zero, have DisplayLink::notifyObserversDisplayWasRefreshed() send
+        EventDispatcher IPC at full framerate, while passing a flag based on the usual
+        relevantForUpdateFrequency() about whether to update the main thread for a given update.
+
+        Allow DisplayLink connection info objects with non-zero fullSpeedUpdatesClientCount
+        to stick around, because that fullSpeedUpdatesClientCount needs to be stored for
+        connections that may not yet have observers.
+
+        Since DisplayLink might have info for connections with no observers, adjust the logic in
+        DisplayLink::notifyObserversDisplayWasRefreshed() to do the CVDisplayLinkStop
+        after traversing the observers.
+
+        The "full speed" client count is maintained by a HysteresisActivity on WebPageProxy,
+        whose impulse is wheel events. This replaces a singleton HysteresisActivity which
+        was used to determine whether IPC goes to EventDispatcher or the main thread of
+        the web process.
+
+        WebPageProxy needs to track the PlatformDisplayID for the screen that its view is on,
+        so it knows which DisplayLink to message.
+
+        * UIProcess/Cocoa/WebProcessPoolCocoa.mm:
+        (WebKit::WebProcessPool::setDisplayLinkForDisplayWantsFullSpeedUpdates):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::m_wheelEventActivityHysteresis):
+        (WebKit::WebPageProxy::wheelEventHysteresisUpdated):
+        (WebKit::WebPageProxy::sendWheelEvent):
+        (WebKit::WebPageProxy::windowScreenDidChange):
+        (WebKit::ScrollingObserver::willSendWheelEvent): Deleted.
+        (WebKit::ScrollingObserver::ScrollingObserver): Deleted.
+        (WebKit::ScrollingObserver::singleton): Deleted.
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebProcessPool.h:
+        * UIProcess/mac/DisplayLink.cpp:
+        (WebKit::DisplayLink::DisplayLink):
+        (WebKit::DisplayLink::~DisplayLink):
+        (WebKit::DisplayLink::addObserver):
+        (WebKit::DisplayLink::removeObserver):
+        (WebKit::DisplayLink::removeInfoForConnectionIfPossible):
+        (WebKit::DisplayLink::incrementFullSpeedRequestClientCount):
+        (WebKit::DisplayLink::decrementFullSpeedRequestClientCount):
+        (WebKit::DisplayLink::setPreferredFramesPerSecond):
+        (WebKit::DisplayLink::notifyObserversDisplayWasRefreshed):
+        * UIProcess/mac/DisplayLink.h:
+        * WebProcess/WebPage/EventDispatcher.cpp:
+        (WebKit::EventDispatcher::displayWasRefreshed):
+        * WebProcess/WebPage/EventDispatcher.h:
+        * WebProcess/WebPage/EventDispatcher.messages.in:
+        * WebProcess/WebPage/mac/DisplayRefreshMonitorMac.cpp:
+        (WebKit::DisplayRefreshMonitorMac::startNotificationMechanism):
+        (WebKit::DisplayRefreshMonitorMac::adjustPreferredFramesPerSecond):
+
 2021-04-02  Chris Dumez  <[email protected]>
 
         Make sure we are no longer show the previous page when running a JS prompt

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm (275439 => 275440)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm	2021-04-02 21:29:13 UTC (rev 275440)
@@ -820,6 +820,20 @@
         }
     }
 }
+
+void WebProcessPool::setDisplayLinkForDisplayWantsFullSpeedUpdates(IPC::Connection& connection, WebCore::PlatformDisplayID displayID, bool wantsFullSpeedUpdates)
+{
+    for (auto& displayLink : m_displayLinks) {
+        if (displayLink->displayID() == displayID) {
+            if (wantsFullSpeedUpdates)
+                displayLink->incrementFullSpeedRequestClientCount(connection);
+            else
+                displayLink->decrementFullSpeedRequestClientCount(connection);
+            return;
+        }
+    }
+}
+
 #endif // HAVE(CVDISPLAYLINK)
 
 // FIXME: Deprecated. Left here until a final decision is made.

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (275439 => 275440)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-04-02 21:29:13 UTC (rev 275440)
@@ -185,7 +185,6 @@
 #include <WebCore/ValidationBubble.h>
 #include <WebCore/WindowFeatures.h>
 #include <WebCore/WritingDirection.h>
-#include <pal/HysteresisActivity.h>
 #include <stdio.h>
 #include <wtf/CallbackAggregator.h>
 #include <wtf/NeverDestroyed.h>
@@ -324,35 +323,6 @@
 
 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageProxyCounter, ("WebPageProxy"));
 
-#if HAVE(CVDISPLAYLINK)
-class ScrollingObserver {
-    WTF_MAKE_NONCOPYABLE(ScrollingObserver);
-    WTF_MAKE_FAST_ALLOCATED;
-    friend NeverDestroyed<ScrollingObserver>;
-public:
-    static ScrollingObserver& singleton();
-
-    void willSendWheelEvent()
-    {
-        m_hysteresis.impulse();
-    }
-
-private:
-    ScrollingObserver()
-        : m_hysteresis([](PAL::HysteresisState state) { DisplayLink::setShouldSendIPCOnBackgroundQueue(state == PAL::HysteresisState::Started); })
-    {
-    }
-
-    PAL::HysteresisActivity m_hysteresis;
-};
-
-ScrollingObserver& ScrollingObserver::singleton()
-{
-    static NeverDestroyed<ScrollingObserver> detector;
-    return detector;
-}
-#endif
-
 class StorageRequests {
     WTF_MAKE_NONCOPYABLE(StorageRequests); WTF_MAKE_FAST_ALLOCATED;
     friend NeverDestroyed<StorageRequests>;
@@ -512,6 +482,9 @@
     , m_backForwardList(WebBackForwardList::create(*this))
     , m_waitsForPaintAfterViewDidMoveToWindow(m_configuration->waitsForPaintAfterViewDidMoveToWindow())
     , m_hasRunningProcess(process.state() != WebProcessProxy::State::Terminated)
+#if HAVE(CVDISPLAYLINK)
+    , m_wheelEventActivityHysteresis([this](PAL::HysteresisState state) { wheelEventHysteresisUpdated(state); })
+#endif
     , m_controlledByAutomation(m_configuration->isControlledByAutomation())
 #if PLATFORM(COCOA)
     , m_isSmartInsertDeleteEnabled(TextChecker::isSmartInsertDeleteEnabled())
@@ -2756,10 +2729,21 @@
     }
 }
 
+#if HAVE(CVDISPLAYLINK)
+void WebPageProxy::wheelEventHysteresisUpdated(PAL::HysteresisState state)
+{
+    if (!m_process->hasConnection() || !m_displayID)
+        return;
+
+    bool wantsFullSpeedUpdates = state == PAL::HysteresisState::Started;
+    process().processPool().setDisplayLinkForDisplayWantsFullSpeedUpdates(*m_process->connection(), *m_displayID, wantsFullSpeedUpdates);
+}
+#endif
+
 void WebPageProxy::sendWheelEvent(const WebWheelEvent& event)
 {
 #if HAVE(CVDISPLAYLINK)
-    ScrollingObserver::singleton().willSendWheelEvent();
+    m_wheelEventActivityHysteresis.impulse();
 #endif
 
     send(
@@ -3776,6 +3760,8 @@
 
 void WebPageProxy::windowScreenDidChange(PlatformDisplayID displayID, Optional<unsigned> nominalFramesPerSecond)
 {
+    m_displayID = displayID;
+
     if (!hasRunningProcess())
         return;
 

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (275439 => 275440)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-04-02 21:29:13 UTC (rev 275440)
@@ -112,6 +112,7 @@
 #include <WebCore/UserInterfaceLayoutDirection.h>
 #include <WebCore/ViewportArguments.h>
 #include <memory>
+#include <pal/HysteresisActivity.h>
 #include <wtf/CompletionHandler.h>
 #include <wtf/FileSystem.h>
 #include <wtf/HashMap.h>
@@ -2300,6 +2301,10 @@
 
     WebWheelEventCoalescer& wheelEventCoalescer();
 
+#if HAVE(CVDISPLAYLINK)
+    void wheelEventHysteresisUpdated(PAL::HysteresisState);
+#endif
+
 #if ENABLE(TOUCH_EVENTS)
     void updateTouchEventTracking(const WebTouchEvent&);
     WebCore::TrackingType touchEventTrackingType(const WebTouchEvent&) const;
@@ -2659,6 +2664,11 @@
 
     std::unique_ptr<WebWheelEventCoalescer> m_wheelEventCoalescer;
 
+    Optional<WebCore::PlatformDisplayID> m_displayID;
+#if HAVE(CVDISPLAYLINK)
+    PAL::HysteresisActivity m_wheelEventActivityHysteresis;
+#endif
+
     Deque<NativeWebMouseEvent> m_mouseEventQueue;
     Deque<NativeWebKeyboardEvent> m_keyEventQueue;
 #if ENABLE(MAC_GESTURE_EVENTS)

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (275439 => 275440)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.h	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h	2021-04-02 21:29:13 UTC (rev 275440)
@@ -243,6 +243,8 @@
     void stopDisplayLink(IPC::Connection&, DisplayLinkObserverID, WebCore::PlatformDisplayID);
     void setDisplayLinkPreferredFramesPerSecond(IPC::Connection&, DisplayLinkObserverID, WebCore::PlatformDisplayID, WebCore::FramesPerSecond);
     void stopDisplayLinks(IPC::Connection&);
+
+    void setDisplayLinkForDisplayWantsFullSpeedUpdates(IPC::Connection&, WebCore::PlatformDisplayID, bool wantsFullSpeedUpdates);
 #endif
 
     void addSupportedPlugin(String&& matchingDomain, String&& name, HashSet<String>&& mimeTypes, HashSet<String> extensions);

Modified: trunk/Source/WebKit/UIProcess/mac/DisplayLink.cpp (275439 => 275440)


--- trunk/Source/WebKit/UIProcess/mac/DisplayLink.cpp	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/UIProcess/mac/DisplayLink.cpp	2021-04-02 21:29:13 UTC (rev 275440)
@@ -60,12 +60,12 @@
 
     m_displayNominalFramesPerSecond = nominalFramesPerSecondFromDisplayLink(m_displayLink);
 
-    LOG_WITH_STREAM(DisplayLink, stream << "[UI ] Creating DisplayLink for display " << displayID << " with nominal fps " << m_displayNominalFramesPerSecond);
+    LOG_WITH_STREAM(DisplayLink, stream << "[UI ] Created DisplayLink " << this << " for display " << displayID << " with nominal fps " << m_displayNominalFramesPerSecond);
 }
 
 DisplayLink::~DisplayLink()
 {
-    LOG_WITH_STREAM(DisplayLink, stream << "[UI ] Destroying DisplayLink for display " << m_displayID);
+    LOG_WITH_STREAM(DisplayLink, stream << "[UI ] Destroying DisplayLink " << this << " for display " << m_displayID);
 
     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
     ASSERT(m_displayLink);
@@ -86,11 +86,13 @@
 {
     ASSERT(RunLoop::isMain());
 
+    LOG_WITH_STREAM(DisplayLink, stream << "[UI ] DisplayLink " << this << " for display display " << m_displayID << " add observer " << observerID << " fps " << preferredFramesPerSecond);
+
     {
         auto locker = holdLock(m_observersLock);
         m_observers.ensure(&connection, [] {
-            return Vector<ObserverInfo> { };
-        }).iterator->value.append({ observerID, preferredFramesPerSecond });
+            return ConnectionClientInfo { };
+        }).iterator->value.observers.append({ observerID, preferredFramesPerSecond });
     }
 
     if (!CVDisplayLinkIsRunning(m_displayLink)) {
@@ -112,13 +114,18 @@
     auto it = m_observers.find(&connection);
     if (it == m_observers.end())
         return;
-    bool removed = it->value.removeFirstMatching([observerID](const auto& value) {
+
+    auto& connectionInfo = it->value;
+
+    bool removed = connectionInfo.observers.removeFirstMatching([observerID](const auto& value) {
         return value.observerID == observerID;
     });
     ASSERT_UNUSED(removed, removed);
-    if (it->value.isEmpty())
-        m_observers.remove(it);
 
+    LOG_WITH_STREAM(DisplayLink, stream << "[UI ] DisplayLink " << this << " for display " << m_displayID << " remove observer " << observerID);
+
+    removeInfoForConnectionIfPossible(connection);
+
     // We do not stop the display link right away when |m_observers| becomes empty. Instead, we
     // let the display link fire up to |maxFireCountWithoutObservers| times without observers to avoid
     // killing & restarting too many threads when observers gets removed & added in quick succession.
@@ -136,9 +143,45 @@
     // killing & restarting too many threads when observers gets removed & added in quick succession.
 }
 
+void DisplayLink::removeInfoForConnectionIfPossible(IPC::Connection& connection)
+{
+    auto it = m_observers.find(&connection);
+    if (it == m_observers.end())
+        return;
+
+    auto& connectionInfo = it->value;
+    if (connectionInfo.observers.isEmpty() && !connectionInfo.fullSpeedUpdatesClientCount)
+        m_observers.remove(it);
+}
+
+void DisplayLink::incrementFullSpeedRequestClientCount(IPC::Connection& connection)
+{
+    auto locker = holdLock(m_observersLock);
+
+    auto& connectionInfo = m_observers.ensure(&connection, [] {
+        return ConnectionClientInfo { };
+    }).iterator->value;;
+
+    ++connectionInfo.fullSpeedUpdatesClientCount;
+}
+
+void DisplayLink::decrementFullSpeedRequestClientCount(IPC::Connection& connection)
+{
+    auto locker = holdLock(m_observersLock);
+
+    auto it = m_observers.find(&connection);
+    if (it == m_observers.end())
+        return;
+
+    auto& connectionInfo = it->value;
+    ASSERT(connectionInfo.fullSpeedUpdatesClientCount);
+    --connectionInfo.fullSpeedUpdatesClientCount;
+    removeInfoForConnectionIfPossible(connection);
+}
+
 void DisplayLink::setPreferredFramesPerSecond(IPC::Connection& connection, DisplayLinkObserverID observerID, WebCore::FramesPerSecond preferredFramesPerSecond)
 {
-    LOG_WITH_STREAM(DisplayLink, stream << "[UI ] DisplayLink::setPreferredFramesPerSecond - display " << m_displayID << " observer " << observerID << " fps " << preferredFramesPerSecond);
+    LOG_WITH_STREAM(DisplayLink, stream << "[UI ] DisplayLink " << this << " setPreferredFramesPerSecond - display " << m_displayID << " observer " << observerID << " fps " << preferredFramesPerSecond);
 
     auto locker = holdLock(m_observersLock);
 
@@ -146,12 +189,13 @@
     if (it == m_observers.end())
         return;
 
-    auto index = it->value.findMatching([observerID](const auto& observer) {
+    auto& connectionInfo = it->value;
+    auto index = connectionInfo.observers.findMatching([observerID](const auto& observer) {
         return observer.observerID == observerID;
     });
 
     if (index != notFound)
-        it->value[index].preferredFramesPerSecond = preferredFramesPerSecond;
+        connectionInfo.observers[index].preferredFramesPerSecond = preferredFramesPerSecond;
 }
 
 CVReturn DisplayLink::displayLinkCallback(CVDisplayLinkRef displayLinkRef, const CVTimeStamp*, const CVTimeStamp*, CVOptionFlags, CVOptionFlags*, void* data)
@@ -165,14 +209,6 @@
     ASSERT(!RunLoop::isMain());
 
     auto locker = holdLock(m_observersLock);
-    if (m_observers.isEmpty()) {
-        if (++m_fireCountWithoutObservers >= maxFireCountWithoutObservers) {
-            LOG_WITH_STREAM(DisplayLink, stream << "[UI ] DisplayLink for display " << m_displayID << " fired " << m_fireCountWithoutObservers << " times with no observers; stopping CVDisplayLink");
-            CVDisplayLinkStop(m_displayLink);
-        }
-        return;
-    }
-    m_fireCountWithoutObservers = 0;
 
     auto maxFramesPerSecond = [](const Vector<ObserverInfo>& observers) {
         Optional<WebCore::FramesPerSecond> observersMaxFramesPerSecond;
@@ -181,23 +217,35 @@
         return observersMaxFramesPerSecond;
     };
 
-    for (auto& [connection, observers] : m_observers) {
-        auto observersMaxFramesPerSecond = maxFramesPerSecond(observers);
-        auto updateIsRelevant = m_currentUpdate.relevantForUpdateFrequency(observersMaxFramesPerSecond.valueOr(WebCore::FullSpeedFramesPerSecond));
+    bool anyConnectionHadObservers = false;
+    for (auto& [connection, connectionInfo] : m_observers) {
+        if (connectionInfo.observers.isEmpty())
+            continue;
 
-        LOG_WITH_STREAM(DisplayLink, stream << "[UI ] DisplayLink for display " << m_displayID << " (display fps " << m_displayNominalFramesPerSecond << ") update " << m_currentUpdate << " " << observers.size()
-            << " observers, on background queue " << shouldSendIPCOnBackgroundQueue << " maxFramesPerSecond " << observersMaxFramesPerSecond << " relevant " << updateIsRelevant);
+        anyConnectionHadObservers = true;
 
-        if (!updateIsRelevant)
-            continue;
+        auto observersMaxFramesPerSecond = maxFramesPerSecond(connectionInfo.observers);
+        auto mainThreadWantsUpdate = m_currentUpdate.relevantForUpdateFrequency(observersMaxFramesPerSecond.valueOr(WebCore::FullSpeedFramesPerSecond));
 
-        if (shouldSendIPCOnBackgroundQueue)
-            connection->send(Messages::EventDispatcher::DisplayWasRefreshed(m_displayID, m_currentUpdate), 0);
-        else
+        LOG_WITH_STREAM(DisplayLink, stream << "[UI ] DisplayLink " << this << " for display " << m_displayID << " (display fps " << m_displayNominalFramesPerSecond << ") update " << m_currentUpdate << " " << connectionInfo.observers.size()
+            << " observers, on background queue " << shouldSendIPCOnBackgroundQueue << " maxFramesPerSecond " << observersMaxFramesPerSecond << " full speed clients " << connectionInfo.fullSpeedUpdatesClientCount << " relevant " << mainThreadWantsUpdate);
+
+        if (connectionInfo.fullSpeedUpdatesClientCount) {
+            connection->send(Messages::EventDispatcher::DisplayWasRefreshed(m_displayID, m_currentUpdate, mainThreadWantsUpdate), 0);
+        } else if (mainThreadWantsUpdate)
             connection->send(Messages::WebProcess::DisplayWasRefreshed(m_displayID, m_currentUpdate), 0);
     }
 
     m_currentUpdate = m_currentUpdate.nextUpdate();
+
+    if (!anyConnectionHadObservers) {
+        if (++m_fireCountWithoutObservers >= maxFireCountWithoutObservers) {
+            LOG_WITH_STREAM(DisplayLink, stream << "[UI ] DisplayLink for display " << m_displayID << " fired " << m_fireCountWithoutObservers << " times with no observers; stopping CVDisplayLink");
+            CVDisplayLinkStop(m_displayLink);
+        }
+        return;
+    }
+    m_fireCountWithoutObservers = 0;
 }
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/mac/DisplayLink.h (275439 => 275440)


--- trunk/Source/WebKit/UIProcess/mac/DisplayLink.h	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/UIProcess/mac/DisplayLink.h	2021-04-02 21:29:13 UTC (rev 275440)
@@ -51,6 +51,9 @@
     void removeObserver(IPC::Connection&, DisplayLinkObserverID);
     void removeObservers(IPC::Connection&);
 
+    void incrementFullSpeedRequestClientCount(IPC::Connection&);
+    void decrementFullSpeedRequestClientCount(IPC::Connection&);
+
     void setPreferredFramesPerSecond(IPC::Connection&, DisplayLinkObserverID, WebCore::FramesPerSecond);
 
     WebCore::PlatformDisplayID displayID() const { return m_displayID; }
@@ -64,7 +67,9 @@
 private:
     static CVReturn displayLinkCallback(CVDisplayLinkRef, const CVTimeStamp*, const CVTimeStamp*, CVOptionFlags, CVOptionFlags*, void* data);
     void notifyObserversDisplayWasRefreshed();
-    
+
+    void removeInfoForConnectionIfPossible(IPC::Connection&);
+
     static WebCore::FramesPerSecond nominalFramesPerSecondFromDisplayLink(CVDisplayLinkRef);
 
     struct ObserverInfo {
@@ -71,10 +76,15 @@
         DisplayLinkObserverID observerID;
         WebCore::FramesPerSecond preferredFramesPerSecond;
     };
+    
+    struct ConnectionClientInfo {
+        unsigned fullSpeedUpdatesClientCount { 0 };
+        Vector<ObserverInfo> observers;
+    };
 
     CVDisplayLinkRef m_displayLink { nullptr };
     Lock m_observersLock;
-    HashMap<RefPtr<IPC::Connection>, Vector<ObserverInfo>> m_observers;
+    HashMap<RefPtr<IPC::Connection>, ConnectionClientInfo> m_observers;
     WebCore::PlatformDisplayID m_displayID;
     WebCore::FramesPerSecond m_displayNominalFramesPerSecond { 0 };
     WebCore::DisplayUpdate m_currentUpdate;

Modified: trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.cpp (275439 => 275440)


--- trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.cpp	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.cpp	2021-04-02 21:29:13 UTC (rev 275440)
@@ -289,11 +289,14 @@
 }
 
 #if HAVE(CVDISPLAYLINK)
-void EventDispatcher::displayWasRefreshed(PlatformDisplayID displayID, const DisplayUpdate& displayUpdate)
+void EventDispatcher::displayWasRefreshed(PlatformDisplayID displayID, const DisplayUpdate& displayUpdate, bool sendToMainThread)
 {
     ASSERT(!RunLoop::isMain());
     notifyScrollingTreesDisplayWasRefreshed(displayID);
 
+    if (!sendToMainThread)
+        return;
+
     RunLoop::main().dispatch([displayID, displayUpdate]() {
         DisplayRefreshMonitorManager::sharedManager().displayWasUpdated(displayID, displayUpdate);
     });

Modified: trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.h (275439 => 275440)


--- trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.h	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.h	2021-04-02 21:29:13 UTC (rev 275440)
@@ -108,7 +108,7 @@
 #endif
 
 #if PLATFORM(MAC)
-    void displayWasRefreshed(WebCore::PlatformDisplayID, const WebCore::DisplayUpdate&);
+    void displayWasRefreshed(WebCore::PlatformDisplayID, const WebCore::DisplayUpdate&, bool sendToMainThread);
 #endif
 
 #if ENABLE(SCROLLING_THREAD)

Modified: trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.messages.in (275439 => 275440)


--- trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.messages.in	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/WebProcess/WebPage/EventDispatcher.messages.in	2021-04-02 21:29:13 UTC (rev 275440)
@@ -30,6 +30,6 @@
     GestureEvent(WebCore::PageIdentifier pageID, WebKit::WebGestureEvent event)
 #endif
 #if HAVE(CVDISPLAYLINK)
-    DisplayWasRefreshed(uint32_t displayID, struct WebCore::DisplayUpdate update)
+    DisplayWasRefreshed(uint32_t displayID, struct WebCore::DisplayUpdate update, bool sendToMainThread)
 #endif
 }

Modified: trunk/Source/WebKit/WebProcess/WebPage/mac/DisplayRefreshMonitorMac.cpp (275439 => 275440)


--- trunk/Source/WebKit/WebProcess/WebPage/mac/DisplayRefreshMonitorMac.cpp	2021-04-02 21:20:45 UTC (rev 275439)
+++ trunk/Source/WebKit/WebProcess/WebPage/mac/DisplayRefreshMonitorMac.cpp	2021-04-02 21:29:13 UTC (rev 275440)
@@ -71,7 +71,7 @@
     if (m_displayLinkIsActive)
         return true;
 
-    LOG_WITH_STREAM(DisplayLink, stream << "DisplayRefreshMonitorMac::requestRefreshCallback - starting");
+    LOG_WITH_STREAM(DisplayLink, stream << "[Web ] DisplayRefreshMonitorMac::requestRefreshCallback for display " << displayID() << " - starting");
     WebProcess::singleton().parentProcessConnection()->send(Messages::WebProcessProxy::StartDisplayLink(m_observerID, displayID(), maxClientPreferredFramesPerSecond().valueOr(FullSpeedFramesPerSecond)), 0);
     if (!m_runLoopObserver) {
         // The RunLoopObserver repeats.
@@ -100,7 +100,7 @@
 
 void DisplayRefreshMonitorMac::adjustPreferredFramesPerSecond(FramesPerSecond preferredFramesPerSecond)
 {
-    LOG_WITH_STREAM(DisplayLink, stream << "DisplayRefreshMonitorMac::adjustPreferredFramesPerSecond for display link on display " << displayID() << " to " << preferredFramesPerSecond);
+    LOG_WITH_STREAM(DisplayLink, stream << "[Web] DisplayRefreshMonitorMac::adjustPreferredFramesPerSecond for display link on display " << displayID() << " to " << preferredFramesPerSecond);
     WebProcess::singleton().parentProcessConnection()->send(Messages::WebProcessProxy::SetDisplayLinkPreferredFramesPerSecond(m_observerID, displayID(), preferredFramesPerSecond), 0);
 
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to