Title: [177144] trunk/Source/WebKit2
Revision
177144
Author
[email protected]
Date
2014-12-11 03:22:30 -0800 (Thu, 11 Dec 2014)

Log Message

[GTK] Timers might never be fired during animations
https://bugs.webkit.org/show_bug.cgi?id=139062

Reviewed by Martin Robinson.

This can happen in old/slow machines where the time to render
layers might take more than 0.016. Since the layer flush timer is
using a higher priority than WebCore timers, when scheduling all
(or several) layer flushes immediately, no other sources with
lower priority are dispatched in the main loop. We could detect if
we are scheduling layer flushes immediately for too long (100ms)
and schedule the next flush after a delay to ensure other sources
with lower priority have a chance to be dispatched. Also use a
lower priority, GDK_PRIORITY_EVENTS is too high, so we use
GDK_PRIORITY_REDRAW - 1 to ensure it's higher than WebCore timers.

* WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp:
(WebKit::LayerTreeHostGtk::LayerTreeHostGtk): Rename
m_lastFlushTime as m_lastImmediateFlushTime.
(WebKit::LayerTreeHostGtk::layerFlushTimerFired): Save the
fireTime before calling flushAndRenderLayers() and compute the
next flush delay based on the elapsed time using monotonically
increasing time instead of current time. Use the target delay
as next flush delay if we have scheduled flushes immediately for
more than 100ms.
(WebKit::LayerTreeHostGtk::flushAndRenderLayers): Do not save the
layer flush time here, it's done in layerFlushTimerFired() so that
we don't need to keep it as a member.
(WebKit::LayerTreeHostGtk::scheduleLayerFlush): Use global
layerFlushTimerPriority.
* WebProcess/WebPage/gtk/LayerTreeHostGtk.h:

Modified Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (177143 => 177144)


--- trunk/Source/WebKit2/ChangeLog	2014-12-11 10:31:28 UTC (rev 177143)
+++ trunk/Source/WebKit2/ChangeLog	2014-12-11 11:22:30 UTC (rev 177144)
@@ -1,3 +1,37 @@
+2014-12-11  Carlos Garcia Campos  <[email protected]>
+
+        [GTK] Timers might never be fired during animations
+        https://bugs.webkit.org/show_bug.cgi?id=139062
+
+        Reviewed by Martin Robinson.
+
+        This can happen in old/slow machines where the time to render
+        layers might take more than 0.016. Since the layer flush timer is
+        using a higher priority than WebCore timers, when scheduling all
+        (or several) layer flushes immediately, no other sources with
+        lower priority are dispatched in the main loop. We could detect if
+        we are scheduling layer flushes immediately for too long (100ms)
+        and schedule the next flush after a delay to ensure other sources
+        with lower priority have a chance to be dispatched. Also use a
+        lower priority, GDK_PRIORITY_EVENTS is too high, so we use
+        GDK_PRIORITY_REDRAW - 1 to ensure it's higher than WebCore timers.
+
+        * WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp:
+        (WebKit::LayerTreeHostGtk::LayerTreeHostGtk): Rename
+        m_lastFlushTime as m_lastImmediateFlushTime.
+        (WebKit::LayerTreeHostGtk::layerFlushTimerFired): Save the
+        fireTime before calling flushAndRenderLayers() and compute the
+        next flush delay based on the elapsed time using monotonically
+        increasing time instead of current time. Use the target delay
+        as next flush delay if we have scheduled flushes immediately for
+        more than 100ms.
+        (WebKit::LayerTreeHostGtk::flushAndRenderLayers): Do not save the
+        layer flush time here, it's done in layerFlushTimerFired() so that
+        we don't need to keep it as a member.
+        (WebKit::LayerTreeHostGtk::scheduleLayerFlush): Use global
+        layerFlushTimerPriority.
+        * WebProcess/WebPage/gtk/LayerTreeHostGtk.h:
+
 2014-12-10  Jaehun Lim  <[email protected]>
 
         [CMake] Fix build after WebStorageNamespaceProvider

Modified: trunk/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp (177143 => 177144)


--- trunk/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp	2014-12-11 10:31:28 UTC (rev 177143)
+++ trunk/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp	2014-12-11 11:22:30 UTC (rev 177144)
@@ -72,7 +72,7 @@
     : LayerTreeHost(webPage)
     , m_isValid(true)
     , m_notifyAfterScheduledLayerFlush(false)
-    , m_lastFlushTime(0)
+    , m_lastImmediateFlushTime(0)
     , m_layerFlushSchedulingEnabled(true)
 {
 }
@@ -251,16 +251,44 @@
     // FIXME: Draw page overlays. https://bugs.webkit.org/show_bug.cgi?id=131433.
 }
 
+static inline bool shouldSkipNextFrameBecauseOfContinousImmediateFlushes(double current, double lastImmediateFlushTime)
+{
+    // 100ms is about a perceptable delay in UI, so when scheduling layer flushes immediately for more than 100ms,
+    // we skip the next frame to ensure pending timers have a change to be fired.
+    static const double maxDurationOfImmediateFlushes = 0.100;
+    if (!lastImmediateFlushTime)
+        return false;
+    return lastImmediateFlushTime + maxDurationOfImmediateFlushes < current;
+}
+
+// Use a higher priority than WebCore timers.
+static const int layerFlushTimerPriority = GDK_PRIORITY_REDRAW - 1;
+
 void LayerTreeHostGtk::layerFlushTimerFired()
 {
+    double fireTime = monotonicallyIncreasingTime();
     flushAndRenderLayers();
+    if (m_layerFlushTimerCallback.isScheduled() || !downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer()->descendantsOrSelfHaveRunningAnimations())
+        return;
 
-    if (!m_layerFlushTimerCallback.isScheduled() && downcast<GraphicsLayerTextureMapper>(*m_rootLayer).layer()->descendantsOrSelfHaveRunningAnimations()) {
-        const double targetFPS = 60;
-        double nextFlush = std::max((1 / targetFPS) - (currentTime() - m_lastFlushTime), 0.0);
-        m_layerFlushTimerCallback.scheduleAfterDelay("[WebKit] layerFlushTimer", std::bind(&LayerTreeHostGtk::layerFlushTimerFired, this),
-            std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(nextFlush)), GDK_PRIORITY_EVENTS);
+    static const double targetFramerate = 1 / 60.0;
+    // When rendering layers takes more time than the target delay (0.016), we end up scheduling layer flushes
+    // immediately. Since the layer flush timer has a higher priority than WebCore timers, these are never
+    // fired while we keep scheduling layer flushes immediately.
+    double current = monotonicallyIncreasingTime();
+    double timeToNextFlush = std::max(targetFramerate - (current - fireTime), 0.0);
+    if (timeToNextFlush)
+        m_lastImmediateFlushTime = 0;
+    else if (!m_lastImmediateFlushTime)
+        m_lastImmediateFlushTime = current;
+
+    if (shouldSkipNextFrameBecauseOfContinousImmediateFlushes(current, m_lastImmediateFlushTime)) {
+        timeToNextFlush = targetFramerate;
+        m_lastImmediateFlushTime = 0;
     }
+
+    m_layerFlushTimerCallback.scheduleAfterDelay("[WebKit] layerFlushTimer", std::bind(&LayerTreeHostGtk::layerFlushTimerFired, this),
+        std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::duration<double>(timeToNextFlush)), layerFlushTimerPriority);
 }
 
 bool LayerTreeHostGtk::flushPendingLayerChanges()
@@ -313,7 +341,6 @@
     if (!context || !context->makeContextCurrent())
         return;
 
-    m_lastFlushTime = currentTime();
     if (!flushPendingLayerChanges())
         return;
 
@@ -359,7 +386,7 @@
 
     // We use a GLib timer because otherwise GTK+ event handling during dragging can starve WebCore timers, which have a lower priority.
     if (!m_layerFlushTimerCallback.isScheduled())
-        m_layerFlushTimerCallback.schedule("[WebKit] layerFlushTimer", std::bind(&LayerTreeHostGtk::layerFlushTimerFired, this), GDK_PRIORITY_EVENTS);
+        m_layerFlushTimerCallback.schedule("[WebKit] layerFlushTimer", std::bind(&LayerTreeHostGtk::layerFlushTimerFired, this), layerFlushTimerPriority);
 }
 
 void LayerTreeHostGtk::setLayerFlushSchedulingEnabled(bool layerFlushingEnabled)

Modified: trunk/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.h (177143 => 177144)


--- trunk/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.h	2014-12-11 10:31:28 UTC (rev 177143)
+++ trunk/Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.h	2014-12-11 11:22:30 UTC (rev 177144)
@@ -100,7 +100,7 @@
     PageOverlayLayerMap m_pageOverlayLayers;
     std::unique_ptr<WebCore::TextureMapper> m_textureMapper;
     OwnPtr<WebCore::GLContext> m_context;
-    double m_lastFlushTime;
+    double m_lastImmediateFlushTime;
     bool m_layerFlushSchedulingEnabled;
     GMainLoopSource m_layerFlushTimerCallback;
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to