Skip to content

Commit

Permalink
Merge r177144 - [GTK] Timers might never be fired during animations
Browse files Browse the repository at this point in the history
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:

Canonical link: https://commits.webkit.org/154760.279@webkitgtk/2.6
git-svn-id: https://svn.webkit.org/repository/webkit/releases/WebKitGTK/webkit-2.6@178348 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
carlosgcampos committed Jan 13, 2015
1 parent ee7d3ac commit 857f149
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 9 deletions.
34 changes: 34 additions & 0 deletions Source/WebKit2/ChangeLog
@@ -1,3 +1,37 @@
2014-12-11 Carlos Garcia Campos <cgarcia@igalia.com>

[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-09 Chris Dumez <cdumez@apple.com>

[WK2] Crash when answering notification permission request after navigating
Expand Down
43 changes: 35 additions & 8 deletions Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.cpp
Expand Up @@ -72,7 +72,7 @@ LayerTreeHostGtk::LayerTreeHostGtk(WebPage* webPage)
: LayerTreeHost(webPage)
, m_isValid(true)
, m_notifyAfterScheduledLayerFlush(false)
, m_lastFlushTime(0)
, m_lastImmediateFlushTime(0)
, m_layerFlushSchedulingEnabled(true)
{
}
Expand Down Expand Up @@ -273,16 +273,44 @@ void LayerTreeHostGtk::paintContents(const GraphicsLayer* graphicsLayer, Graphic
// 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() || !toTextureMapperLayer(m_rootLayer.get())->descendantsOrSelfHaveRunningAnimations())
return;

if (!m_layerFlushTimerCallback.isScheduled() && toTextureMapperLayer(m_rootLayer.get())->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()
Expand Down Expand Up @@ -335,7 +363,6 @@ void LayerTreeHostGtk::flushAndRenderLayers()
if (!context || !context->makeContextCurrent())
return;

m_lastFlushTime = currentTime();
if (!flushPendingLayerChanges())
return;

Expand Down Expand Up @@ -381,7 +408,7 @@ void LayerTreeHostGtk::scheduleLayerFlush()

// 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)
Expand Down
2 changes: 1 addition & 1 deletion Source/WebKit2/WebProcess/WebPage/gtk/LayerTreeHostGtk.h
Expand Up @@ -103,7 +103,7 @@ class LayerTreeHostGtk final : public LayerTreeHost, WebCore::GraphicsLayerClien
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;
};
Expand Down

0 comments on commit 857f149

Please sign in to comment.