Throttle compositing layer flushes during page loading
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Apr 2013 21:19:56 +0000 (21:19 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Apr 2013 21:19:56 +0000 (21:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=113786

Reviewed by Simon Fraser.

Page content can change rapidly during page loading triggering excessive layer flushes and repainting. We should avoid this unnecessary work.

This patch reduces layer flushes (and painting) during loading by 50-70% on many popular pages.

* loader/FrameLoader.cpp:
(WebCore::FrameLoader::loadProgressingStatusChanged):
* loader/FrameLoader.h:
* loader/ProgressTracker.cpp:
(WebCore::ProgressTracker::ProgressTracker):
(WebCore::ProgressTracker::reset):
(WebCore::ProgressTracker::progressStarted):
(WebCore::ProgressTracker::finalProgressComplete):
(WebCore::ProgressTracker::isLoadProgressing):
(WebCore::ProgressTracker::progressHeartbeatTimerFired):
* loader/ProgressTracker.h:

    Track if the document load is progressing. This is done with a heartbeat timer that checks every 100ms if we have received more than 1k of data.
    If four heartbeats pass without progress then we consider the load stalled.

* page/FrameView.cpp:
(WebCore::FrameView::resetDeferredRepaintDelay):

    Disable throttling temporary on user interaction so the page stays as responsive as possible even during loading.

(WebCore::FrameView::updateLayerFlushThrottling):

    Enable throttling when the load is progressing, disable otherwise.

* page/FrameView.h:
* platform/graphics/GraphicsLayer.h:
(WebCore::GraphicsLayer::canThrottleLayerFlush):
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::platformCALayerDidCreateTiles):
(WebCore::GraphicsLayerCA::canThrottleLayerFlush):

    Don't throttle if new tiles have been added by the tile controller. They may have stale content and need to be flushed immediately.

(WebCore::GraphicsLayerCA::noteLayerPropertyChanged):

    Set the new TilesAdded change flag.

* platform/graphics/ca/GraphicsLayerCA.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::notifyFlushRequired):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::RenderLayerCompositor):
(WebCore::RenderLayerCompositor::notifyFlushRequired):
(WebCore::RenderLayerCompositor::scheduleLayerFlushNow):

    Factor the actual flush scheduling to private function.

(WebCore::RenderLayerCompositor::scheduleLayerFlush):

    Mark the compositor for flush and return without flushing if the flushes are currently being throttled.

(WebCore::RenderLayerCompositor::flushPendingLayerChanges):

    After a flush, start the throtting timer (currently 0.5s) coalescing the subsequent flushes.

(WebCore::RenderLayerCompositor::didChangeVisibleRect):

    Do immediately flush if needed.

(WebCore::RenderLayerCompositor::setLayerFlushThrottlingEnabled):

    Flush immediately if disabled.

(WebCore::RenderLayerCompositor::disableLayerFlushThrottlingTemporarilyForInteraction):
(WebCore::RenderLayerCompositor::isThrottlingLayerFlushes):
(WebCore::RenderLayerCompositor::startLayerFlushTimerIfNeeded):
(WebCore::RenderLayerCompositor::layerFlushTimerFired):

    Flush when the timer fires timer.

* rendering/RenderLayerCompositor.h:

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

13 files changed:
Source/WebCore/ChangeLog
Source/WebCore/loader/FrameLoader.cpp
Source/WebCore/loader/FrameLoader.h
Source/WebCore/loader/ProgressTracker.cpp
Source/WebCore/loader/ProgressTracker.h
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/FrameView.h
Source/WebCore/platform/graphics/GraphicsLayer.h
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderLayerCompositor.h

index 0c4bbe6..4d3bad5 100644 (file)
@@ -1,3 +1,86 @@
+2013-04-05  Antti Koivisto  <antti@apple.com>
+
+        Throttle compositing layer flushes during page loading
+        https://bugs.webkit.org/show_bug.cgi?id=113786
+
+        Reviewed by Simon Fraser.
+        
+        Page content can change rapidly during page loading triggering excessive layer flushes and repainting. We should avoid this unnecessary work.
+        
+        This patch reduces layer flushes (and painting) during loading by 50-70% on many popular pages.
+
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::loadProgressingStatusChanged):        
+        * loader/FrameLoader.h:
+        * loader/ProgressTracker.cpp:
+        (WebCore::ProgressTracker::ProgressTracker):
+        (WebCore::ProgressTracker::reset):
+        (WebCore::ProgressTracker::progressStarted):
+        (WebCore::ProgressTracker::finalProgressComplete):
+        (WebCore::ProgressTracker::isLoadProgressing):
+        (WebCore::ProgressTracker::progressHeartbeatTimerFired):
+        * loader/ProgressTracker.h:
+        
+            Track if the document load is progressing. This is done with a heartbeat timer that checks every 100ms if we have received more than 1k of data.
+            If four heartbeats pass without progress then we consider the load stalled.
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::resetDeferredRepaintDelay):
+        
+            Disable throttling temporary on user interaction so the page stays as responsive as possible even during loading.
+
+        (WebCore::FrameView::updateLayerFlushThrottling):
+        
+            Enable throttling when the load is progressing, disable otherwise.
+
+        * page/FrameView.h:
+        * platform/graphics/GraphicsLayer.h:
+        (WebCore::GraphicsLayer::canThrottleLayerFlush):
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::GraphicsLayerCA::platformCALayerDidCreateTiles):
+        (WebCore::GraphicsLayerCA::canThrottleLayerFlush):
+        
+            Don't throttle if new tiles have been added by the tile controller. They may have stale content and need to be flushed immediately.
+
+        (WebCore::GraphicsLayerCA::noteLayerPropertyChanged):
+        
+            Set the new TilesAdded change flag.
+
+        * platform/graphics/ca/GraphicsLayerCA.h:
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::notifyFlushRequired):
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::RenderLayerCompositor):
+        (WebCore::RenderLayerCompositor::notifyFlushRequired):
+        (WebCore::RenderLayerCompositor::scheduleLayerFlushNow):
+        
+            Factor the actual flush scheduling to private function.
+
+        (WebCore::RenderLayerCompositor::scheduleLayerFlush):
+        
+            Mark the compositor for flush and return without flushing if the flushes are currently being throttled.
+
+        (WebCore::RenderLayerCompositor::flushPendingLayerChanges):
+        
+            After a flush, start the throtting timer (currently 0.5s) coalescing the subsequent flushes.
+
+        (WebCore::RenderLayerCompositor::didChangeVisibleRect):
+        
+            Do immediately flush if needed.
+
+        (WebCore::RenderLayerCompositor::setLayerFlushThrottlingEnabled):
+        
+            Flush immediately if disabled.
+
+        (WebCore::RenderLayerCompositor::disableLayerFlushThrottlingTemporarilyForInteraction):
+        (WebCore::RenderLayerCompositor::isThrottlingLayerFlushes):
+        (WebCore::RenderLayerCompositor::startLayerFlushTimerIfNeeded):
+        (WebCore::RenderLayerCompositor::layerFlushTimerFired):
+        
+            Flush when the timer fires timer.
+
+        * rendering/RenderLayerCompositor.h:
+
 2013-04-05  Benjamin Poulain  <benjamin@webkit.org>
 
         Clean the chromium bits of WebCore's WebDatabase
index b98d0c5..7fb589a 100644 (file)
@@ -3316,6 +3316,12 @@ NetworkingContext* FrameLoader::networkingContext() const
     return m_networkingContext.get();
 }
 
+void FrameLoader::loadProgressingStatusChanged()
+{
+    bool isLoadProgressing = m_frame->page()->progress()->isLoadProgressing();
+    m_frame->page()->mainFrame()->view()->updateLayerFlushThrottling(isLoadProgressing);
+}
+
 void FrameLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 {
     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader);
index d87b4bb..38ce3ac 100644 (file)
@@ -281,6 +281,8 @@ public:
 
     NetworkingContext* networkingContext() const;
 
+    void loadProgressingStatusChanged();
+
     const KURL& previousURL() const { return m_previousURL; }
 
     void reportMemoryUsage(MemoryObjectInfo*) const;
index 92388ec..867c027 100644 (file)
@@ -51,6 +51,13 @@ static const double finalProgressValue = 0.9; // 1.0 - initialProgressValue
 
 static const int progressItemDefaultEstimatedLength = 1024 * 16;
 
+// Check if the load is progressing this often.
+static const double progressHeartbeatInterval = 0.1;
+// How many heartbeats must pass without progress before deciding the load is currently stalled.
+static const unsigned loadStalledHeartbeatCount = 4;
+// How many bytes are required between heartbeats to consider it progress.
+static const unsigned minumumBytesPerHeartbeatForProgress = 1024;
+
 struct ProgressItem {
     WTF_MAKE_NONCOPYABLE(ProgressItem); WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -74,6 +81,9 @@ ProgressTracker::ProgressTracker()
     , m_finalProgressChangedSent(false)
     , m_progressValue(0)
     , m_numProgressTrackedFrames(0)
+    , m_progressHeartbeatTimer(this, &ProgressTracker::progressHeartbeatTimerFired)
+    , m_heartbeatsWithNoProgress(0)
+    , m_totalBytesReceivedBeforePreviousHeartbeat(0)
 {
 }
 
@@ -103,6 +113,10 @@ void ProgressTracker::reset()
     m_finalProgressChangedSent = false;
     m_numProgressTrackedFrames = 0;
     m_originatingProgressFrame = 0;
+
+    m_heartbeatsWithNoProgress = 0;
+    m_totalBytesReceivedBeforePreviousHeartbeat = 0;
+    m_progressHeartbeatTimer.stop();
 }
 
 void ProgressTracker::progressStarted(Frame* frame)
@@ -115,7 +129,10 @@ void ProgressTracker::progressStarted(Frame* frame)
         reset();
         m_progressValue = initialProgressValue;
         m_originatingProgressFrame = frame;
-    
+
+        m_progressHeartbeatTimer.startRepeating(progressHeartbeatInterval);
+        m_originatingProgressFrame->loader()->loadProgressingStatusChanged();
+
         m_originatingProgressFrame->loader()->client()->postProgressStartedNotification();
     }
     m_numProgressTrackedFrames++;
@@ -157,6 +174,8 @@ void ProgressTracker::finalProgressComplete()
 
     frame->loader()->client()->setMainFrameDocumentReady(true);
     frame->loader()->client()->postProgressFinishedNotification();
+    frame->loader()->loadProgressingStatusChanged();
+
     InspectorInstrumentation::frameStoppedLoading(frame.get());
 }
 
@@ -264,5 +283,24 @@ unsigned long ProgressTracker::createUniqueIdentifier()
     return ++s_uniqueIdentifier;
 }
 
+bool ProgressTracker::isLoadProgressing() const
+{
+    return m_progressValue && m_progressValue < finalProgressValue && m_heartbeatsWithNoProgress < loadStalledHeartbeatCount;
+}
+
+void ProgressTracker::progressHeartbeatTimerFired(Timer<ProgressTracker>*)
+{
+    if (m_totalBytesReceived < m_totalBytesReceivedBeforePreviousHeartbeat + minumumBytesPerHeartbeatForProgress)
+        ++m_heartbeatsWithNoProgress;
+    else
+        m_heartbeatsWithNoProgress = 0;
+
+    m_totalBytesReceivedBeforePreviousHeartbeat = m_totalBytesReceived;
+
+    m_originatingProgressFrame->loader()->loadProgressingStatusChanged();
+
+    if (m_progressValue >= finalProgressValue)
+        m_progressHeartbeatTimer.stop();
+}
 
 }
index ddacff2..604c434 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef ProgressTracker_h
 #define ProgressTracker_h
 
+#include "Timer.h"
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/Noncopyable.h>
@@ -58,11 +59,15 @@ public:
     long long totalPageAndResourceBytesToLoad() const { return m_totalPageAndResourceBytesToLoad; }
     long long totalBytesReceived() const { return m_totalBytesReceived; }
 
+    bool isLoadProgressing() const;
+
 private:
     ProgressTracker();
 
     void reset();
     void finalProgressComplete();
+
+    void progressHeartbeatTimerFired(Timer<ProgressTracker>*);
     
     static unsigned long s_uniqueIdentifier;
     
@@ -78,6 +83,10 @@ private:
     
     int m_numProgressTrackedFrames;
     HashMap<unsigned long, OwnPtr<ProgressItem> > m_progressItems;
+
+    Timer<ProgressTracker> m_progressHeartbeatTimer;
+    unsigned m_heartbeatsWithNoProgress;
+    long long m_totalBytesReceivedBeforePreviousHeartbeat;
 };
     
 }
index b2911d9..4c7c8da 100644 (file)
@@ -2258,6 +2258,10 @@ void FrameView::resetDeferredRepaintDelay()
         if (!m_deferringRepaints)
             doDeferredRepaints();
     }
+#if USE(ACCELERATED_COMPOSITING)
+    if (RenderView* view = renderView())
+        view->compositor()->disableLayerFlushThrottlingTemporarilyForInteraction();
+#endif
 }
 
 double FrameView::adjustedDeferredRepaintDelay() const
@@ -2285,6 +2289,16 @@ void FrameView::endDisableRepaints()
     m_disableRepaints--;
 }
 
+void FrameView::updateLayerFlushThrottling(bool isLoadProgressing)
+{
+#if USE(ACCELERATED_COMPOSITING)
+    if (RenderView* view = renderView())
+        view->compositor()->setLayerFlushThrottlingEnabled(isLoadProgressing);
+#else
+    UNUSED_PARAM(isLoadProgressing);
+#endif
+}
+
 void FrameView::layoutTimerFired(Timer<FrameView>*)
 {
 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
index 2950410..7ba4ad6 100644 (file)
@@ -236,6 +236,8 @@ public:
     void startDeferredRepaintTimer(double delay);
     void resetDeferredRepaintDelay();
 
+    void updateLayerFlushThrottling(bool isLoadProgressing);
+
     void beginDisableRepaints();
     void endDisableRepaints();
     bool repaintsDisabled() { return m_disableRepaints > 0; }
index 33bbb6f..2f0e3d1 100644 (file)
@@ -437,6 +437,8 @@ public:
 
     void updateDebugIndicators();
 
+    virtual bool canThrottleLayerFlush() const { return false; }
+
     virtual void reportMemoryUsage(MemoryObjectInfo*) const;
 
 protected:
index 306943e..b1e8463 100644 (file)
@@ -1110,9 +1110,7 @@ void GraphicsLayerCA::platformCALayerDidCreateTiles(const Vector<FloatRect>& dir
     for (size_t i = 0; i < dirtyRects.size(); ++i)
         setNeedsDisplayInRect(dirtyRects[i]);
 
-    // Ensure that the layout is up to date before any individual tiles are painted by telling the client
-    // that it needs to flush its layer state, which will end up scheduling the layer flusher.
-    client()->notifyFlushRequired(this);
+    noteLayerPropertyChanged(TilesAdded);
 }
 
 float GraphicsLayerCA::platformCALayerDeviceScaleFactor()
@@ -3052,12 +3050,22 @@ void GraphicsLayerCA::noteSublayersChanged()
     propagateLayerChangeToReplicas();
 }
 
+bool GraphicsLayerCA::canThrottleLayerFlush() const
+{
+    // Tile layers are currently plain CA layers, attached directly by TileController. They require immediate flush as they may contain garbage.
+    return !(m_uncommittedChanges & TilesAdded);
+}
+
 void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags)
 {
-    if (!m_uncommittedChanges && m_client)
-        m_client->notifyFlushRequired(this);
+    bool hadUncommittedChanges = !!m_uncommittedChanges;
+    bool oldCanThrottleLayerFlush = canThrottleLayerFlush();
 
     m_uncommittedChanges |= flags;
+
+    bool needsFlush = !hadUncommittedChanges || oldCanThrottleLayerFlush != canThrottleLayerFlush();
+    if (needsFlush && m_client)
+        m_client->notifyFlushRequired(this);
 }
 
 double GraphicsLayerCA::backingStoreMemoryEstimate() const
index 9a68a6c..7b35cac 100644 (file)
@@ -254,6 +254,8 @@ private:
 
     bool recursiveVisibleRectChangeRequiresFlush(const TransformState&) const;
 
+    virtual bool canThrottleLayerFlush() const;
+
     // Used to track the path down the tree for replica layers.
     struct ReplicaState {
         static const size_t maxReplicaDepth = 16;
@@ -397,7 +399,8 @@ private:
         ContentsVisibilityChanged = 1 << 25,
         VisibleRectChanged = 1 << 26,
         FiltersChanged = 1 << 27,
-        DebugIndicatorsChanged = 1 << 28
+        TilesAdded = 1 < 28,
+        DebugIndicatorsChanged = 1 << 29
     };
     typedef unsigned LayerChangeFlags;
     void noteLayerPropertyChanged(LayerChangeFlags flags);
index ddb0753..ff3a5d4 100644 (file)
@@ -2148,10 +2148,11 @@ void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double tim
     renderer()->animation()->notifyAnimationStarted(renderer(), time);
 }
 
-void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer*)
+void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer* layer)
 {
-    if (!renderer()->documentBeingDestroyed())
-        compositor()->scheduleLayerFlush();
+    if (renderer()->documentBeingDestroyed())
+        return;
+    compositor()->scheduleLayerFlush(layer->canThrottleLayerFlush());
 }
 
 void RenderLayerBacking::notifyFlushBeforeDisplayRefresh(const GraphicsLayer* layer)
index 955ce79..9dbbb1d 100644 (file)
@@ -84,10 +84,12 @@ bool WebCoreHas3DRendering = true;
 #define WTF_USE_COMPOSITING_FOR_SMALL_CANVASES 1
 #endif
 
-static const int canvasAreaThresholdRequiringCompositing = 50 * 100;
-
 namespace WebCore {
 
+static const int canvasAreaThresholdRequiringCompositing = 50 * 100;
+// During page loading delay layer flushes up to this many seconds to allow them coalesce, reducing workload.
+static const double throttledLayerFlushDelay = .5;
+
 using namespace HTMLNames;
 
 class RenderLayerCompositor::OverlapMap {
@@ -211,6 +213,10 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView)
     , m_isTrackingRepaints(false)
     , m_layersWithTiledBackingCount(0)
     , m_rootLayerAttachment(RootLayerUnattached)
+    , m_layerFlushTimer(this, &RenderLayerCompositor::layerFlushTimerFired)
+    , m_layerFlushThrottlingEnabled(false)
+    , m_layerFlushThrottlingTemporarilyDisabledForInteraction(false)
+    , m_hasPendingLayerFlush(false)
 #if !LOG_DISABLED
     , m_rootLayerUpdateCount(0)
     , m_obligateCompositedLayerCount(0)
@@ -317,12 +323,27 @@ void RenderLayerCompositor::customPositionForVisibleRectComputation(const Graphi
     position = -scrollPosition;
 }
 
-void RenderLayerCompositor::scheduleLayerFlush()
+void RenderLayerCompositor::notifyFlushRequired(const GraphicsLayer* layer)
+{
+    scheduleLayerFlush(layer->canThrottleLayerFlush());
+}
+
+void RenderLayerCompositor::scheduleLayerFlushNow()
 {
+    m_hasPendingLayerFlush = false;
     if (Page* page = this->page())
         page->chrome()->client()->scheduleCompositingLayerFlush();
 }
 
+void RenderLayerCompositor::scheduleLayerFlush(bool canThrottle)
+{
+    if (canThrottle && isThrottlingLayerFlushes()) {
+        m_hasPendingLayerFlush = true;
+        return;
+    }
+    scheduleLayerFlushNow();
+}
+
 void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot)
 {
     // FrameView::flushCompositingStateIncludingSubframes() flushes each subframe,
@@ -361,6 +382,7 @@ void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot)
         
         m_viewportConstrainedLayersNeedingUpdate.clear();
     }
+    startLayerFlushTimerIfNeeded();
 }
 
 void RenderLayerCompositor::didFlushChangesForLayer(RenderLayer* layer, const GraphicsLayer* graphicsLayer)
@@ -384,8 +406,9 @@ void RenderLayerCompositor::didChangeVisibleRect()
         return;
 
     IntRect visibleRect = m_clipLayer ? IntRect(IntPoint(), frameView->contentsSize()) : frameView->visibleContentRect();
-    if (rootLayer->visibleRectChangeRequiresFlush(visibleRect))
-        scheduleLayerFlush();
+    if (!rootLayer->visibleRectChangeRequiresFlush(visibleRect))
+        return;
+    scheduleLayerFlushNow();
 }
 
 void RenderLayerCompositor::notifyFlushBeforeDisplayRefresh(const GraphicsLayer*)
@@ -3124,6 +3147,51 @@ Page* RenderLayerCompositor::page() const
     return 0;
 }
 
+void RenderLayerCompositor::setLayerFlushThrottlingEnabled(bool enabled)
+{
+    m_layerFlushThrottlingEnabled = enabled;
+    if (m_layerFlushThrottlingEnabled)
+        return;
+    m_layerFlushTimer.stop();
+    if (!m_hasPendingLayerFlush)
+        return;
+    scheduleLayerFlushNow();
+}
+
+void RenderLayerCompositor::disableLayerFlushThrottlingTemporarilyForInteraction()
+{
+    if (m_layerFlushThrottlingTemporarilyDisabledForInteraction)
+        return;
+    m_layerFlushThrottlingTemporarilyDisabledForInteraction = true;
+}
+
+bool RenderLayerCompositor::isThrottlingLayerFlushes() const
+{
+    if (!m_layerFlushThrottlingEnabled)
+        return false;
+    if (!m_layerFlushTimer.isActive())
+        return false;
+    if (m_layerFlushThrottlingTemporarilyDisabledForInteraction)
+        return false;
+    return true;
+}
+
+void RenderLayerCompositor::startLayerFlushTimerIfNeeded()
+{
+    m_layerFlushThrottlingTemporarilyDisabledForInteraction = false;
+    m_layerFlushTimer.stop();
+    if (!m_layerFlushThrottlingEnabled)
+        return;
+    m_layerFlushTimer.startOneShot(throttledLayerFlushDelay);
+}
+
+void RenderLayerCompositor::layerFlushTimerFired(Timer<RenderLayerCompositor>*)
+{
+    if (!m_hasPendingLayerFlush)
+        return;
+    scheduleLayerFlushNow();
+}
+
 void RenderLayerCompositor::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 {
     MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::Rendering);
index b8cdf61..25a1d19 100644 (file)
@@ -126,7 +126,7 @@ public:
     
     // GraphicsLayers buffer state, which gets pushed to the underlying platform layers
     // at specific times.
-    void scheduleLayerFlush();
+    void scheduleLayerFlush(bool canThrottle);
     void flushPendingLayerChanges(bool isFlushRoot = true);
     
     // flushPendingLayerChanges() flushes the entire GraphicsLayer tree, which can cross frame boundaries.
@@ -277,13 +277,16 @@ public:
     bool hasNonMainLayersWithTiledBacking() const { return m_layersWithTiledBackingCount; }
 
     CompositingReasons reasonsForCompositing(const RenderLayer*) const;
-    
+
+    void setLayerFlushThrottlingEnabled(bool);
+    void disableLayerFlushThrottlingTemporarilyForInteraction();
+
 private:
     class OverlapMap;
 
     // GraphicsLayerClient implementation
     virtual void notifyAnimationStarted(const GraphicsLayer*, double) OVERRIDE { }
-    virtual void notifyFlushRequired(const GraphicsLayer*) OVERRIDE { scheduleLayerFlush(); }
+    virtual void notifyFlushRequired(const GraphicsLayer*) OVERRIDE;
     virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect&) OVERRIDE;
 
     virtual bool isTrackingRepaints() const OVERRIDE;
@@ -380,6 +383,11 @@ private:
     bool requiresContentShadowLayer() const;
 #endif
 
+    void scheduleLayerFlushNow();
+    bool isThrottlingLayerFlushes() const;
+    void startLayerFlushTimerIfNeeded();
+    void layerFlushTimerFired(Timer<RenderLayerCompositor>*);
+
 #if !LOG_DISABLED
     const char* logReasonsForCompositing(const RenderLayer*);
     void logLayerInfo(const RenderLayer*, int depth);
@@ -441,6 +449,11 @@ private:
 
     OwnPtr<GraphicsLayerUpdater> m_layerUpdater; // Updates tiled layer visible area periodically while animations are running.
 
+    Timer<RenderLayerCompositor> m_layerFlushTimer;
+    bool m_layerFlushThrottlingEnabled;
+    bool m_layerFlushThrottlingTemporarilyDisabledForInteraction;
+    bool m_hasPendingLayerFlush;
+
 #if !LOG_DISABLED
     int m_rootLayerUpdateCount;
     int m_obligateCompositedLayerCount; // count of layer that have to be composited.