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;
};