[GTK] Use the DisplayRefreshMonitor facilities
authorzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Apr 2017 06:50:50 +0000 (06:50 +0000)
committerzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Apr 2017 06:50:50 +0000 (06:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170599

Reviewed by Carlos Garcia Campos.

Source/WebCore:

* CMakeLists.txt: Add missing files to the build.
* platform/graphics/DisplayRefreshMonitor.cpp: Build fixes.
(WebCore::DisplayRefreshMonitor::createDefaultDisplayRefreshMonitor):
* platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp:
(WebCore::CoordinatedGraphicsLayer::updatePlatformLayer): Mark the
platform layer as updated in the layer's CoordinatedGraphicsState.
* platform/graphics/texmap/coordinated/CoordinatedGraphicsState.h:

Source/WebKit2:

ThreadedCompositor gains a DisplayRefreshMonitor member that it can use
to better coordinate display refresh callbacks on the main thread. Still,
because currently the GTK+ port doesn't have a reliable way of notifying
the ThreadedCompositor of a vsync event, a timer targeting 60FPS is used
in order to keep the updates at a reasonable rate. When the timer is fired,
the ThreadedCompositor decides how to proceed based on state changes that
might have occurred during composition or whether there's any display
refresh callbacks that require handling on the main thread.

CompositingRunLoop now stores its state in an atomic variable that's then
inspected whenever a new update is scheduled or completed. When scheduled,
if there's no update in progress, a new update is requested through the
timer. If there's already an update in progress, a new update is marked
as pending after the current one completes. In that case, when the update
is completed, a new update is requested through the timer.

ThreadedDisplayRefreshMonitor is used to coordinate updates between the
main and the composition thread whenever the CoordinatedGraphics state
demands it, or whenever there are clients registered to that monitor that
require an update (e.g. a requestAnimationFrame() callback). After the
update on the composition thread is finished, and the DisplayRefreshMonitor
object requires an update, a callback at the same priority as the layer
flush timer is scheduled on the main thread. In that callback we handle
any clients registered for this DisplayRefreshMonitor before proceeding
to handle any changes to the CoordinatedGraphics scene. In case the
DisplayRefreshMonitor clients or the layer flushes already queued up
any changes to the state, we immediately ask the ThreadedCompositor for
an update.

* PlatformGTK.cmake:
* Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp:
(WebKit::CoordinatedGraphicsScene::updateViewport):
(WebKit::CoordinatedGraphicsScene::commitSceneState):
* Shared/CoordinatedGraphics/CoordinatedGraphicsScene.h:
* Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.cpp:
(WebKit::CompositingRunLoop::CompositingRunLoop):
(WebKit::CompositingRunLoop::isActive):
(WebKit::CompositingRunLoop::scheduleUpdate):
(WebKit::CompositingRunLoop::stopUpdates):
(WebKit::CompositingRunLoop::updateCompleted):
(WebKit::CompositingRunLoop::updateTimerFired):
(WebKit::CompositingRunLoop::isCurrent):
(WebKit::CompositingRunLoop::startUpdateTimer): Deleted.
(WebKit::CompositingRunLoop::stopUpdateTimer): Deleted.
* Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h:
(): Deleted.
* Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp:
(WebKit::m_displayRefreshMonitor):
(WebKit::ThreadedCompositor::invalidate):
(WebKit::ThreadedCompositor::setNativeSurfaceHandleForCompositing):
(WebKit::ThreadedCompositor::updateViewport):
(WebKit::ThreadedCompositor::scheduleDisplayImmediately):
(WebKit::ThreadedCompositor::renderLayerTree):
(WebKit::ThreadedCompositor::sceneUpdateFinished):
(WebKit::ThreadedCompositor::updateSceneState):
(WebKit::ThreadedCompositor::displayRefreshMonitor):
(WebKit::ThreadedCompositor::renderNextFrameIfNeeded):
(WebKit::ThreadedCompositor::completeCoordinatedUpdateIfNeeded):
(WebKit::ThreadedCompositor::coordinateUpdateCompletionWithClient):
(WebKit::ThreadedCompositor::performFrameCompletion):
* Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h:
* Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp: Added.
(WebKit::ThreadedDisplayRefreshMonitor::ThreadedDisplayRefreshMonitor):
(WebKit::ThreadedDisplayRefreshMonitor::requestRefreshCallback):
(WebKit::ThreadedDisplayRefreshMonitor::requiresDisplayRefreshCallback):
(WebKit::ThreadedDisplayRefreshMonitor::dispatchDisplayRefreshCallback):
(WebKit::ThreadedDisplayRefreshMonitor::invalidate):
(WebKit::ThreadedDisplayRefreshMonitor::displayRefreshCallback):
* Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.h: Copied from Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h.
* WebProcess/WebPage/AcceleratedDrawingArea.cpp:
(WebKit::AcceleratedDrawingArea::createDisplayRefreshMonitor):
* WebProcess/WebPage/AcceleratedDrawingArea.h:
* WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.cpp:
(WebKit::ThreadedCoordinatedLayerTreeHost::createDisplayRefreshMonitor):
* WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.h:
* WebProcess/WebPage/LayerTreeHost.h:
(WebKit::LayerTreeHost::createDisplayRefreshMonitor):

Source/WTF:

* wtf/Platform.h: Enable USE_REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR for the GTK+ port.
* wtf/glib/RunLoopSourcePriority.h: Add the DisplayRefreshMonitorTimer entry that
matches the value of LayerFlushTimer.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@215259 268f45cc-cd09-0410-ab3c-d52691b4dbfc

23 files changed:
Source/WTF/ChangeLog
Source/WTF/wtf/Platform.h
Source/WTF/wtf/glib/RunLoopSourcePriority.h
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/DisplayRefreshMonitor.cpp
Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp
Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsState.h
Source/WebKit2/ChangeLog
Source/WebKit2/PlatformGTK.cmake
Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp
Source/WebKit2/Shared/CoordinatedGraphics/CoordinatedGraphicsScene.h
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.cpp
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp [new file with mode: 0644]
Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.h [new file with mode: 0644]
Source/WebKit2/WebProcess/WebPage/AcceleratedDrawingArea.cpp
Source/WebKit2/WebProcess/WebPage/AcceleratedDrawingArea.h
Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.cpp
Source/WebKit2/WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.h
Source/WebKit2/WebProcess/WebPage/LayerTreeHost.h

index 2dafec7..94f0784 100644 (file)
@@ -1,3 +1,14 @@
+2017-04-11  Zan Dobersek  <zdobersek@igalia.com>
+
+        [GTK] Use the DisplayRefreshMonitor facilities
+        https://bugs.webkit.org/show_bug.cgi?id=170599
+
+        Reviewed by Carlos Garcia Campos.
+
+        * wtf/Platform.h: Enable USE_REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR for the GTK+ port.
+        * wtf/glib/RunLoopSourcePriority.h: Add the DisplayRefreshMonitorTimer entry that
+        matches the value of LayerFlushTimer.
+
 2017-04-11  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [WebCore][JSC] ResourceUsageData.{timeOfNextEdenCollection,timeOfNextFullCollection} should be MonotonicTime
index b5cf682..63df625 100644 (file)
 #define USE_REQUEST_ANIMATION_FRAME_TIMER 1
 #endif
 
-#if PLATFORM(COCOA)
+#if PLATFORM(COCOA) || PLATFORM(GTK)
 #define USE_REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR 1
 #endif
 
index 498dd6b..a1dde13 100644 (file)
@@ -64,6 +64,9 @@ enum RunLoopSourcePriority {
     // Layer flush.
     LayerFlushTimer = -100,
 
+    // DisplayRefreshMonitor timer, should have the same value as the LayerFlushTimer.
+    DisplayRefreshMonitorTimer = -100,
+
     // Rendering timer in the main thread when accelerated compositing is not used.
     NonAcceleratedDrawingTimer = 100
 };
index e06c80d..4058b2c 100644 (file)
@@ -2253,7 +2253,9 @@ set(WebCore_SOURCES
     platform/graphics/Color.cpp
     platform/graphics/ComplexTextController.cpp
     platform/graphics/CrossfadeGeneratedImage.cpp
+    platform/graphics/DisplayRefreshMonitor.cpp
     platform/graphics/DisplayRefreshMonitorClient.cpp
+    platform/graphics/DisplayRefreshMonitorManager.cpp
     platform/graphics/ExtendedColor.cpp
     platform/graphics/FloatPoint.cpp
     platform/graphics/FloatPoint3D.cpp
index a0fb794..0c16232 100644 (file)
@@ -1,3 +1,18 @@
+2017-04-11  Zan Dobersek  <zdobersek@igalia.com>
+
+        [GTK] Use the DisplayRefreshMonitor facilities
+        https://bugs.webkit.org/show_bug.cgi?id=170599
+
+        Reviewed by Carlos Garcia Campos.
+
+        * CMakeLists.txt: Add missing files to the build.
+        * platform/graphics/DisplayRefreshMonitor.cpp: Build fixes.
+        (WebCore::DisplayRefreshMonitor::createDefaultDisplayRefreshMonitor):
+        * platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp:
+        (WebCore::CoordinatedGraphicsLayer::updatePlatformLayer): Mark the
+        platform layer as updated in the layer's CoordinatedGraphicsState.
+        * platform/graphics/texmap/coordinated/CoordinatedGraphicsState.h:
+
 2017-04-11  Antoine Quint  <graouts@apple.com>
 
         [Modern Media Controls] Allow modern-media-controls to be provided through WebKitAdditions
index 2cbefcc..7780ea8 100644 (file)
@@ -33,7 +33,7 @@
 
 #if PLATFORM(IOS)
 #include "DisplayRefreshMonitorIOS.h"
-#else
+#elif PLATFORM(MAC)
 #include "DisplayRefreshMonitorMac.h"
 #endif
 
@@ -47,6 +47,7 @@ RefPtr<DisplayRefreshMonitor> DisplayRefreshMonitor::createDefaultDisplayRefresh
 #if PLATFORM(IOS)
     return DisplayRefreshMonitorIOS::create(displayID);
 #endif
+    UNUSED_PARAM(displayID);
     return nullptr;
 }
 
index 8cbd2be..4fdffb0 100644 (file)
@@ -714,6 +714,7 @@ void CoordinatedGraphicsLayer::updatePlatformLayer()
         return;
 
     m_shouldUpdatePlatformLayer = false;
+    m_layerState.platformLayerUpdated = true;
     if (m_platformLayer)
         m_platformLayer->swapBuffersIfNeeded();
 #endif
index c810530..ed4f34b 100644 (file)
@@ -86,6 +86,7 @@ struct CoordinatedGraphicsLayerState {
             bool childrenChanged: 1;
             bool repaintCountChanged : 1;
             bool platformLayerChanged: 1;
+            bool platformLayerUpdated: 1;
             bool platformLayerShouldSwapBuffers: 1;
             bool isScrollableChanged: 1;
             bool committedScrollOffsetChanged: 1;
index 7f0d471..9c9d5ee 100644 (file)
@@ -1,3 +1,88 @@
+2017-04-11  Zan Dobersek  <zdobersek@igalia.com>
+
+        [GTK] Use the DisplayRefreshMonitor facilities
+        https://bugs.webkit.org/show_bug.cgi?id=170599
+
+        Reviewed by Carlos Garcia Campos.
+
+        ThreadedCompositor gains a DisplayRefreshMonitor member that it can use
+        to better coordinate display refresh callbacks on the main thread. Still,
+        because currently the GTK+ port doesn't have a reliable way of notifying
+        the ThreadedCompositor of a vsync event, a timer targeting 60FPS is used
+        in order to keep the updates at a reasonable rate. When the timer is fired,
+        the ThreadedCompositor decides how to proceed based on state changes that
+        might have occurred during composition or whether there's any display
+        refresh callbacks that require handling on the main thread.
+
+        CompositingRunLoop now stores its state in an atomic variable that's then
+        inspected whenever a new update is scheduled or completed. When scheduled,
+        if there's no update in progress, a new update is requested through the
+        timer. If there's already an update in progress, a new update is marked
+        as pending after the current one completes. In that case, when the update
+        is completed, a new update is requested through the timer.
+
+        ThreadedDisplayRefreshMonitor is used to coordinate updates between the
+        main and the composition thread whenever the CoordinatedGraphics state
+        demands it, or whenever there are clients registered to that monitor that
+        require an update (e.g. a requestAnimationFrame() callback). After the
+        update on the composition thread is finished, and the DisplayRefreshMonitor
+        object requires an update, a callback at the same priority as the layer
+        flush timer is scheduled on the main thread. In that callback we handle
+        any clients registered for this DisplayRefreshMonitor before proceeding
+        to handle any changes to the CoordinatedGraphics scene. In case the
+        DisplayRefreshMonitor clients or the layer flushes already queued up
+        any changes to the state, we immediately ask the ThreadedCompositor for
+        an update.
+
+        * PlatformGTK.cmake:
+        * Shared/CoordinatedGraphics/CoordinatedGraphicsScene.cpp:
+        (WebKit::CoordinatedGraphicsScene::updateViewport):
+        (WebKit::CoordinatedGraphicsScene::commitSceneState):
+        * Shared/CoordinatedGraphics/CoordinatedGraphicsScene.h:
+        * Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.cpp:
+        (WebKit::CompositingRunLoop::CompositingRunLoop):
+        (WebKit::CompositingRunLoop::isActive):
+        (WebKit::CompositingRunLoop::scheduleUpdate):
+        (WebKit::CompositingRunLoop::stopUpdates):
+        (WebKit::CompositingRunLoop::updateCompleted):
+        (WebKit::CompositingRunLoop::updateTimerFired):
+        (WebKit::CompositingRunLoop::isCurrent):
+        (WebKit::CompositingRunLoop::startUpdateTimer): Deleted.
+        (WebKit::CompositingRunLoop::stopUpdateTimer): Deleted.
+        * Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h:
+        (): Deleted.
+        * Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp:
+        (WebKit::m_displayRefreshMonitor):
+        (WebKit::ThreadedCompositor::invalidate):
+        (WebKit::ThreadedCompositor::setNativeSurfaceHandleForCompositing):
+        (WebKit::ThreadedCompositor::updateViewport):
+        (WebKit::ThreadedCompositor::scheduleDisplayImmediately):
+        (WebKit::ThreadedCompositor::renderLayerTree):
+        (WebKit::ThreadedCompositor::sceneUpdateFinished):
+        (WebKit::ThreadedCompositor::updateSceneState):
+        (WebKit::ThreadedCompositor::displayRefreshMonitor):
+        (WebKit::ThreadedCompositor::renderNextFrameIfNeeded):
+        (WebKit::ThreadedCompositor::completeCoordinatedUpdateIfNeeded):
+        (WebKit::ThreadedCompositor::coordinateUpdateCompletionWithClient):
+        (WebKit::ThreadedCompositor::performFrameCompletion):
+        * Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h:
+        * Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp: Added.
+        (WebKit::ThreadedDisplayRefreshMonitor::ThreadedDisplayRefreshMonitor):
+        (WebKit::ThreadedDisplayRefreshMonitor::requestRefreshCallback):
+        (WebKit::ThreadedDisplayRefreshMonitor::requiresDisplayRefreshCallback):
+        (WebKit::ThreadedDisplayRefreshMonitor::dispatchDisplayRefreshCallback):
+        (WebKit::ThreadedDisplayRefreshMonitor::invalidate):
+        (WebKit::ThreadedDisplayRefreshMonitor::displayRefreshCallback):
+        * Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.h: Copied from Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.h.
+        * WebProcess/WebPage/AcceleratedDrawingArea.cpp:
+        (WebKit::AcceleratedDrawingArea::createDisplayRefreshMonitor):
+        * WebProcess/WebPage/AcceleratedDrawingArea.h:
+        * WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.cpp:
+        (WebKit::ThreadedCoordinatedLayerTreeHost::createDisplayRefreshMonitor):
+        * WebProcess/WebPage/CoordinatedGraphics/ThreadedCoordinatedLayerTreeHost.h:
+        * WebProcess/WebPage/LayerTreeHost.h:
+        (WebKit::LayerTreeHost::createDisplayRefreshMonitor):
+
 2017-04-11  Alex Christensen  <achristensen@webkit.org>
 
         Modernize and clean up code
index 4aa206a..ff250ae 100644 (file)
@@ -65,6 +65,7 @@ list(APPEND WebKit2_SOURCES
 
     Shared/CoordinatedGraphics/threadedcompositor/CompositingRunLoop.cpp
     Shared/CoordinatedGraphics/threadedcompositor/ThreadSafeCoordinatedSurface.cpp
+    Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp
     Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp
 
     Shared/Plugins/Netscape/x11/NetscapePluginModuleX11.cpp
index b94faea..56e6f8b 100644 (file)
@@ -127,12 +127,8 @@ void CoordinatedGraphicsScene::paintToCurrentGLContext(const TransformationMatri
 
 void CoordinatedGraphicsScene::updateViewport()
 {
-    if (!m_client)
-        return;
-    dispatchOnClientRunLoop([this] {
-        if (m_client)
-            m_client->updateViewport();
-    });
+    if (m_client)
+        m_client->updateViewport();
 }
 
 void CoordinatedGraphicsScene::adjustPositionForFixedLayers(const FloatPoint& contentPosition)
@@ -547,9 +543,6 @@ void CoordinatedGraphicsScene::commitSceneState(const CoordinatedGraphicsState&
 
     commitPendingBackingStoreOperations();
     removeReleasedImageBackingsIfNeeded();
-
-    // The pending tiles state is on its way for the screen, tell the web process to render the next one.
-    renderNextFrame();
 }
 
 void CoordinatedGraphicsScene::renderNextFrame()
index 128b7be..99ea7da 100644 (file)
@@ -80,6 +80,7 @@ public:
     void setActive(bool);
 
     void commitSceneState(const WebCore::CoordinatedGraphicsState&);
+    void renderNextFrame();
 
     void setViewBackgroundColor(const WebCore::Color& color) { m_viewBackgroundColor = color; }
     WebCore::Color viewBackgroundColor() const { return m_viewBackgroundColor; }
@@ -123,7 +124,6 @@ private:
     void dispatchOnMainThread(Function<void()>&&);
     void dispatchOnClientRunLoop(Function<void()>&&);
     void updateViewport();
-    void renderNextFrame();
 
     void createLayer(WebCore::CoordinatedLayerID);
     void deleteLayer(WebCore::CoordinatedLayerID);
index 5617bba..8acf506 100644 (file)
@@ -112,6 +112,8 @@ CompositingRunLoop::CompositingRunLoop(std::function<void ()>&& updateFunction)
     : m_updateTimer(WorkQueuePool::singleton().runLoop(this), this, &CompositingRunLoop::updateTimerFired)
     , m_updateFunction(WTFMove(updateFunction))
 {
+    m_updateState.store(UpdateState::Completed);
+
 #if USE(GLIB_EVENT_LOOP)
     m_updateTimer.setPriority(RunLoopSourcePriority::CompositingThreadUpdateTimer);
 #endif
@@ -144,28 +146,44 @@ void CompositingRunLoop::performTaskSync(Function<void ()>&& function)
     m_dispatchSyncCondition.wait(m_dispatchSyncConditionMutex);
 }
 
-void CompositingRunLoop::startUpdateTimer(UpdateTiming timing)
+bool CompositingRunLoop::isActive()
 {
-    if (m_updateTimer.isActive())
-        return;
+    return m_updateState.load() != UpdateState::Completed;
+}
 
-    const static double targetFPS = 60;
-    double nextUpdateTime = 0;
-    if (timing == WaitUntilNextFrame)
-        nextUpdateTime = std::max((1 / targetFPS) - (monotonicallyIncreasingTime() - m_lastUpdateTime), 0.0);
+void CompositingRunLoop::scheduleUpdate()
+{
+    if (m_updateState.compareExchangeStrong(UpdateState::Completed, UpdateState::InProgress) == UpdateState::Completed) {
+        m_updateTimer.startOneShot(0);
+        return;
+    }
 
-    m_updateTimer.startOneShot(1_s * nextUpdateTime);
+    if (m_updateState.compareExchangeStrong(UpdateState::InProgress, UpdateState::PendingAfterCompletion) == UpdateState::InProgress)
+        return;
 }
 
-void CompositingRunLoop::stopUpdateTimer()
+void CompositingRunLoop::stopUpdates()
 {
     m_updateTimer.stop();
+    m_updateState.store(UpdateState::Completed);
+}
+
+void CompositingRunLoop::updateCompleted()
+{
+    if (m_updateState.compareExchangeStrong(UpdateState::InProgress, UpdateState::Completed) == UpdateState::InProgress)
+        return;
+
+    if (m_updateState.compareExchangeStrong(UpdateState::PendingAfterCompletion, UpdateState::InProgress) == UpdateState::PendingAfterCompletion) {
+        m_updateTimer.startOneShot(0);
+        return;
+    }
+
+    ASSERT_NOT_REACHED();
 }
 
 void CompositingRunLoop::updateTimerFired()
 {
     m_updateFunction();
-    m_lastUpdateTime = monotonicallyIncreasingTime();
 }
 
 } // namespace WebKit
index 52b5d7d..6bc9d22 100644 (file)
@@ -28,6 +28,7 @@
 
 #if USE(COORDINATED_GRAPHICS_THREADED)
 
+#include <wtf/Atomics.h>
 #include <wtf/Condition.h>
 #include <wtf/FastMalloc.h>
 #include <wtf/Function.h>
@@ -41,29 +42,39 @@ class CompositingRunLoop {
     WTF_MAKE_NONCOPYABLE(CompositingRunLoop);
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    enum UpdateTiming {
-        Immediate,
-        WaitUntilNextFrame,
-    };
-
     CompositingRunLoop(std::function<void ()>&&);
     ~CompositingRunLoop();
 
     void performTask(Function<void ()>&&);
     void performTaskSync(Function<void ()>&&);
 
-    void startUpdateTimer(UpdateTiming = Immediate);
-    void stopUpdateTimer();
+    bool isActive();
+    void scheduleUpdate();
+    void stopUpdates();
+
+    void updateCompleted();
+
+#ifndef NDEBUG
+    bool isCurrent();
+#endif
 
 private:
+    enum class UpdateState {
+        Completed,
+        InProgress,
+        PendingAfterCompletion,
+    };
+
     void updateTimerFired();
 
     RunLoop::Timer<CompositingRunLoop> m_updateTimer;
+#ifndef NDEBUG
+    RunLoop& m_runLoop;
+#endif
     std::function<void ()> m_updateFunction;
+    Atomic<UpdateState> m_updateState;
     Lock m_dispatchSyncConditionMutex;
     Condition m_dispatchSyncCondition;
-
-    double m_lastUpdateTime { 0 };
 };
 
 } // namespace WebKit
index c7ad837..54d960b 100644 (file)
@@ -29,6 +29,7 @@
 #if USE(COORDINATED_GRAPHICS_THREADED)
 
 #include "CompositingRunLoop.h"
+#include "ThreadedDisplayRefreshMonitor.h"
 #include <WebCore/PlatformDisplay.h>
 #include <WebCore/TransformationMatrix.h>
 
@@ -56,7 +57,13 @@ ThreadedCompositor::ThreadedCompositor(Client& client, const IntSize& viewportSi
     , m_paintFlags(paintFlags)
     , m_needsResize(!viewportSize.isEmpty())
     , m_compositingRunLoop(std::make_unique<CompositingRunLoop>([this] { renderLayerTree(); }))
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    , m_displayRefreshMonitor(ThreadedDisplayRefreshMonitor::create(*this))
+#endif
 {
+    m_clientRendersNextFrame.store(false);
+    m_coordinateUpdateCompletionWithClient.store(false);
+
     m_compositingRunLoop->performTaskSync([this, protectedThis = makeRef(*this)] {
         m_scene = adoptRef(new CoordinatedGraphicsScene(this));
         if (m_nativeSurfaceHandle) {
@@ -89,18 +96,21 @@ void ThreadedCompositor::createGLContext()
 void ThreadedCompositor::invalidate()
 {
     m_scene->detach();
-    m_compositingRunLoop->stopUpdateTimer();
+    m_compositingRunLoop->stopUpdates();
     m_compositingRunLoop->performTaskSync([this, protectedThis = makeRef(*this)] {
         m_scene->purgeGLResources();
         m_context = nullptr;
         m_scene = nullptr;
     });
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    m_displayRefreshMonitor->invalidate();
+#endif
     m_compositingRunLoop = nullptr;
 }
 
 void ThreadedCompositor::setNativeSurfaceHandleForCompositing(uint64_t handle)
 {
-    m_compositingRunLoop->stopUpdateTimer();
+    m_compositingRunLoop->stopUpdates();
     m_compositingRunLoop->performTaskSync([this, protectedThis = makeRef(*this), handle] {
         // A new native handle can't be set without destroying the previous one first if any.
         ASSERT(!!handle ^ !!m_nativeSurfaceHandle);
@@ -119,7 +129,7 @@ void ThreadedCompositor::setScaleFactor(float scale)
 {
     m_compositingRunLoop->performTask([this, protectedThis = makeRef(*this), scale] {
         m_scaleFactor = scale;
-        scheduleDisplayImmediately();
+        m_compositingRunLoop->scheduleUpdate();
     });
 }
 
@@ -128,7 +138,7 @@ void ThreadedCompositor::setScrollPosition(const IntPoint& scrollPosition, float
     m_compositingRunLoop->performTask([this, protectedThis = makeRef(*this), scrollPosition, scale] {
         m_scrollPosition = scrollPosition;
         m_scaleFactor = scale;
-        scheduleDisplayImmediately();
+        m_compositingRunLoop->scheduleUpdate();
     });
 }
 
@@ -138,7 +148,7 @@ void ThreadedCompositor::setViewportSize(const IntSize& viewportSize, float scal
         m_viewportSize = viewportSize;
         m_scaleFactor = scale;
         m_needsResize = true;
-        scheduleDisplayImmediately();
+        m_compositingRunLoop->scheduleUpdate();
     });
 }
 
@@ -146,7 +156,7 @@ void ThreadedCompositor::setDrawsBackground(bool drawsBackground)
 {
     m_compositingRunLoop->performTask([this, protectedThis = Ref<ThreadedCompositor>(*this), drawsBackground] {
         m_drawsBackground = drawsBackground;
-        scheduleDisplayImmediately();
+        m_compositingRunLoop->scheduleUpdate();
     });
 }
 
@@ -164,12 +174,7 @@ void ThreadedCompositor::commitScrollOffset(uint32_t layerID, const IntSize& off
 
 void ThreadedCompositor::updateViewport()
 {
-    m_compositingRunLoop->startUpdateTimer(CompositingRunLoop::WaitUntilNextFrame);
-}
-
-void ThreadedCompositor::scheduleDisplayImmediately()
-{
-    m_compositingRunLoop->startUpdateTimer(CompositingRunLoop::Immediate);
+    m_compositingRunLoop->scheduleUpdate();
 }
 
 void ThreadedCompositor::forceRepaint()
@@ -205,18 +210,65 @@ void ThreadedCompositor::renderLayerTree()
     m_scene->paintToCurrentGLContext(viewportTransform, 1, clipRect, Color::transparent, !m_drawsBackground, m_scrollPosition, m_paintFlags);
 
     m_context->swapBuffers();
+
+    sceneUpdateFinished();
+}
+
+void ThreadedCompositor::sceneUpdateFinished()
+{
+    bool shouldDispatchDisplayRefreshCallback = m_clientRendersNextFrame.load()
+        || m_displayRefreshMonitor->requiresDisplayRefreshCallback();
+    bool shouldCoordinateUpdateCompletionWithClient = m_coordinateUpdateCompletionWithClient.load();
+
+    if (shouldDispatchDisplayRefreshCallback)
+        m_displayRefreshMonitor->dispatchDisplayRefreshCallback();
+    if (!shouldCoordinateUpdateCompletionWithClient)
+        m_compositingRunLoop->updateCompleted();
 }
 
 void ThreadedCompositor::updateSceneState(const CoordinatedGraphicsState& state)
 {
     ASSERT(isMainThread());
     RefPtr<CoordinatedGraphicsScene> scene = m_scene;
-    m_scene->appendUpdate([scene, state] {
+    m_scene->appendUpdate([this, scene, state] {
         scene->commitSceneState(state);
+
+        m_clientRendersNextFrame.store(true);
+        bool coordinateUpdate = std::any_of(state.layersToUpdate.begin(), state.layersToUpdate.end(),
+            [](const std::pair<CoordinatedLayerID, CoordinatedGraphicsLayerState>& it) {
+                return it.second.platformLayerChanged || it.second.platformLayerUpdated;
+            });
+        m_coordinateUpdateCompletionWithClient.store(coordinateUpdate);
     });
 
-    scheduleDisplayImmediately();
+    m_compositingRunLoop->scheduleUpdate();
+}
+
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+RefPtr<WebCore::DisplayRefreshMonitor> ThreadedCompositor::displayRefreshMonitor(PlatformDisplayID)
+{
+    return m_displayRefreshMonitor.copyRef();
+}
+
+void ThreadedCompositor::renderNextFrameIfNeeded()
+{
+    if (m_clientRendersNextFrame.compareExchangeStrong(true, false))
+        m_scene->renderNextFrame();
+}
+
+void ThreadedCompositor::completeCoordinatedUpdateIfNeeded()
+{
+    if (m_coordinateUpdateCompletionWithClient.compareExchangeStrong(true, false))
+        m_compositingRunLoop->updateCompleted();
+}
+
+void ThreadedCompositor::coordinateUpdateCompletionWithClient()
+{
+    m_coordinateUpdateCompletionWithClient.store(true);
+    if (!m_compositingRunLoop->isActive())
+        m_compositingRunLoop->scheduleUpdate();
 }
+#endif
 
 }
 #endif // USE(COORDINATED_GRAPHICS_THREADED)
index bac81a3..67954a0 100644 (file)
 #include <WebCore/GLContext.h>
 #include <WebCore/IntSize.h>
 #include <WebCore/TextureMapper.h>
+#include <wtf/Atomics.h>
 #include <wtf/FastMalloc.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/ThreadSafeRefCounted.h>
 
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+#include <WebCore/DisplayRefreshMonitor.h>
+#endif
+
 namespace WebCore {
 struct CoordinatedGraphicsState;
 }
@@ -45,6 +50,7 @@ namespace WebKit {
 
 class CoordinatedGraphicsScene;
 class CoordinatedGraphicsSceneClient;
+class ThreadedDisplayRefreshMonitor;
 
 class ThreadedCompositor : public CoordinatedGraphicsSceneClient, public ThreadSafeRefCounted<ThreadedCompositor> {
     WTF_MAKE_NONCOPYABLE(ThreadedCompositor);
@@ -73,6 +79,13 @@ public:
 
     void forceRepaint();
 
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    RefPtr<WebCore::DisplayRefreshMonitor> displayRefreshMonitor(WebCore::PlatformDisplayID);
+    void renderNextFrameIfNeeded();
+    void completeCoordinatedUpdateIfNeeded();
+    void coordinateUpdateCompletionWithClient();
+#endif
+
 private:
     ThreadedCompositor(Client&, const WebCore::IntSize&, float scaleFactor, uint64_t nativeSurfaceHandle, ShouldDoFrameSync, WebCore::TextureMapper::PaintFlags);
 
@@ -82,7 +95,7 @@ private:
     void commitScrollOffset(uint32_t layerID, const WebCore::IntSize& offset) override;
 
     void renderLayerTree();
-    void scheduleDisplayImmediately();
+    void sceneUpdateFinished();
 
     void createGLContext();
 
@@ -100,6 +113,13 @@ private:
     bool m_needsResize { false };
 
     std::unique_ptr<CompositingRunLoop> m_compositingRunLoop;
+
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    Ref<ThreadedDisplayRefreshMonitor> m_displayRefreshMonitor;
+#endif
+
+    Atomic<bool> m_clientRendersNextFrame;
+    Atomic<bool> m_coordinateUpdateCompletionWithClient;
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp
new file mode 100644 (file)
index 0000000..7348709
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ThreadedDisplayRefreshMonitor.h"
+
+#if USE(COORDINATED_GRAPHICS_THREADED) && USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+
+#include "CompositingRunLoop.h"
+#include "ThreadedCompositor.h"
+#include <wtf/glib/RunLoopSourcePriority.h>
+
+namespace WebKit {
+
+ThreadedDisplayRefreshMonitor::ThreadedDisplayRefreshMonitor(ThreadedCompositor& compositor)
+    : WebCore::DisplayRefreshMonitor(0)
+    , m_displayRefreshTimer(RunLoop::main(), this, &ThreadedDisplayRefreshMonitor::displayRefreshCallback)
+    , m_compositor(&compositor)
+{
+#if USE(GLIB_EVENT_LOOP)
+    m_displayRefreshTimer.setPriority(RunLoopSourcePriority::DisplayRefreshMonitorTimer);
+#endif
+}
+
+bool ThreadedDisplayRefreshMonitor::requestRefreshCallback()
+{
+    if (!m_compositor)
+        return false;
+
+    LockHolder locker(mutex());
+    setIsScheduled(true);
+
+    if (isPreviousFrameDone())
+        m_compositor->coordinateUpdateCompletionWithClient();
+
+    return true;
+}
+
+bool ThreadedDisplayRefreshMonitor::requiresDisplayRefreshCallback()
+{
+    LockHolder locker(mutex());
+    return isScheduled() && isPreviousFrameDone();
+}
+
+void ThreadedDisplayRefreshMonitor::dispatchDisplayRefreshCallback()
+{
+    m_displayRefreshTimer.startOneShot(0);
+}
+
+void ThreadedDisplayRefreshMonitor::invalidate()
+{
+    m_displayRefreshTimer.stop();
+    m_compositor = nullptr;
+}
+
+void ThreadedDisplayRefreshMonitor::displayRefreshCallback()
+{
+    bool shouldHandleDisplayRefreshNotification = false;
+    {
+        LockHolder locker(mutex());
+        shouldHandleDisplayRefreshNotification = isScheduled() && isPreviousFrameDone();
+        if (shouldHandleDisplayRefreshNotification)
+            setIsPreviousFrameDone(false);
+    }
+
+    if (shouldHandleDisplayRefreshNotification)
+        DisplayRefreshMonitor::handleDisplayRefreshedNotificationOnMainThread(this);
+
+    if (m_compositor) {
+        m_compositor->renderNextFrameIfNeeded();
+        m_compositor->completeCoordinatedUpdateIfNeeded();
+        if (isScheduled())
+            m_compositor->coordinateUpdateCompletionWithClient();
+    }
+}
+
+} // namespace WebKit
+
+#endif // USE(COORDINATED_GRAPHICS_THREADED) && USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
diff --git a/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.h b/Source/WebKit2/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.h
new file mode 100644 (file)
index 0000000..8d46e3d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if USE(COORDINATED_GRAPHICS_THREADED) && USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+
+#include <WebCore/DisplayRefreshMonitor.h>
+#include <wtf/RunLoop.h>
+
+namespace WebKit {
+
+class ThreadedCompositor;
+
+class ThreadedDisplayRefreshMonitor : public WebCore::DisplayRefreshMonitor {
+public:
+    static Ref<ThreadedDisplayRefreshMonitor> create(ThreadedCompositor& compositor)
+    {
+        return adoptRef(*new ThreadedDisplayRefreshMonitor(compositor));
+    }
+    virtual ~ThreadedDisplayRefreshMonitor() = default;
+
+    bool requestRefreshCallback() override;
+
+    bool requiresDisplayRefreshCallback();
+    void dispatchDisplayRefreshCallback();
+    void invalidate();
+
+private:
+    ThreadedDisplayRefreshMonitor(ThreadedCompositor&);
+
+    void displayRefreshCallback();
+    RunLoop::Timer<ThreadedDisplayRefreshMonitor> m_displayRefreshTimer;
+    ThreadedCompositor* m_compositor;
+};
+
+} // namespace WebKit
+
+#endif // USE(COORDINATED_GRAPHICS_THREADED) && USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
index e3c58c8..1ea8a3c 100644 (file)
@@ -223,6 +223,15 @@ void AcceleratedDrawingArea::scheduleCompositingLayerFlushImmediately()
     scheduleCompositingLayerFlush();
 }
 
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+RefPtr<WebCore::DisplayRefreshMonitor> AcceleratedDrawingArea::createDisplayRefreshMonitor(WebCore::PlatformDisplayID displayID)
+{
+    if (!m_layerTreeHost || m_wantsToExitAcceleratedCompositingMode || exitAcceleratedCompositingModePending())
+        return nullptr;
+    return m_layerTreeHost->createDisplayRefreshMonitor(displayID);
+}
+#endif
+
 void AcceleratedDrawingArea::updateBackingStoreState(uint64_t stateID, bool respondImmediately, float deviceScaleFactor, const IntSize& size, const IntSize& scrollOffset)
 {
     ASSERT(!m_inUpdateBackingStoreState);
index ead32ab..72a7bc2 100644 (file)
@@ -59,6 +59,10 @@ protected:
     void scheduleCompositingLayerFlush() override;
     void scheduleCompositingLayerFlushImmediately() override;
 
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    virtual RefPtr<WebCore::DisplayRefreshMonitor> createDisplayRefreshMonitor(WebCore::PlatformDisplayID);
+#endif
+
 #if USE(TEXTURE_MAPPER_GL) && PLATFORM(GTK) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
     void setNativeSurfaceHandleForCompositing(uint64_t) override;
     void destroyNativeSurfaceHandleForCompositing(bool&) override;
index 281353b..60e9167 100644 (file)
@@ -74,7 +74,7 @@ ThreadedCoordinatedLayerTreeHost::ThreadedCoordinatedLayerTreeHost(WebPage& webP
         // Do not do frame sync when rendering offscreen in the web process to ensure that SwapBuffers never blocks.
         // Rendering to the actual screen will happen later anyway since the UI process schedules a redraw for every update,
         // the compositor will take care of syncing to vblank.
-        m_compositor = ThreadedCompositor::create(m_compositorClient, scaledSize, scaleFactor, m_surface->window(), ThreadedCompositor::ShouldDoFrameSync::No, paintFlags);
+        m_compositor = ThreadedCompositor::create(m_compositorClient, scaledSize, scaleFactor, m_surface->window(), ThreadedCompositor::ShouldDoFrameSync::Yes, paintFlags);
         m_layerTreeContext.contextID = m_surface->surfaceID();
     } else
         m_compositor = ThreadedCompositor::create(m_compositorClient, scaledSize, scaleFactor);
@@ -247,6 +247,13 @@ void ThreadedCoordinatedLayerTreeHost::setIsDiscardable(bool discardable)
         didChangeViewport();
 }
 
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+RefPtr<WebCore::DisplayRefreshMonitor> ThreadedCoordinatedLayerTreeHost::createDisplayRefreshMonitor(PlatformDisplayID displayID)
+{
+    return m_compositor->displayRefreshMonitor(displayID);
+}
+#endif
+
 } // namespace WebKit
 
 #endif // USE(COORDINATED_GRAPHICS)
index ca8aeac..26cb52a 100644 (file)
@@ -101,6 +101,10 @@ private:
     void didFlushRootLayer(const WebCore::FloatRect&) override { }
     void commitSceneState(const WebCore::CoordinatedGraphicsState&) override;
 
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    RefPtr<WebCore::DisplayRefreshMonitor> createDisplayRefreshMonitor(WebCore::PlatformDisplayID) override;
+#endif
+
     enum class DiscardableSyncActions {
         UpdateSize = 1 << 1,
         UpdateViewport = 1 << 2,
index 51af581..76c527e 100644 (file)
@@ -29,6 +29,8 @@
 #if USE(COORDINATED_GRAPHICS) || USE(TEXTURE_MAPPER)
 
 #include "LayerTreeContext.h"
+#include <WebCore/DisplayRefreshMonitor.h>
+#include <WebCore/PlatformScreen.h>
 #include <wtf/Forward.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
@@ -96,6 +98,10 @@ public:
     virtual void deviceOrPageScaleFactorChanged() = 0;
 #endif
 
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    virtual RefPtr<WebCore::DisplayRefreshMonitor> createDisplayRefreshMonitor(WebCore::PlatformDisplayID) { return nullptr; }
+#endif
+
     virtual void setViewOverlayRootLayer(WebCore::GraphicsLayer* viewOverlayRootLayer) { m_viewOverlayRootLayer = viewOverlayRootLayer; }
 
 protected: